Main Analysis
After analyzing the quality of the data set, we got rid of data in which the Borough is missing and the year is before 2013.
ViolationsData <- ViolationsData %>% filter (BORO != "Missing")
ViolationsData <- ViolationsData %>% filter(
as.numeric(format(INSPECTION.DATE , '%Y')) > 2012)
Now we can get a better picture of the total number of inspections by year and borough.
boroughPlot <- ggplot(ViolationsData, aes(BORO,fill=BORO))
boroughPlot + geom_bar() + theme(legend.position="none") +
facet_wrap(~factor(as.numeric( format(INSPECTION.DATE , '%Y')))) +
ggtitle("Total Inspections from 2013-2017 in each Borough") +
xlab("Borough") + ylab("Number of Inspections") +
theme(axis.text.x = element_text(angle = 45, hjust = 1))

After 2013, there seems to be a consistent amount of inspections across the years. The number of inspections by borough also seems to make sense since we expect Manhattan to have the largest number of restuarants.
Next, we took a look at the grade distribution by borough.
inspection_grades <- ViolationsData %>% select(-CAMIS, -DBA, -BUILDING, -STREET, -ZIPCODE, -PHONE, -ACTION, -VIOLATION.CODE, -VIOLATION.DESCRIPTION, -CRITICAL.FLAG, -SCORE, -GRADE.DATE, -RECORD.DATE, -INSPECTION.TYPE,-CUISINE.DESCRIPTION)
inspection_grades_woyear<-inspection_grades %>% select(-INSPECTION.DATE)
inspection_grades_woyear <- inspection_grades_woyear %>% gather(key, value, -BORO) %>% group_by(BORO, key, value) %>% tally %>% spread(value, n, fill = 0)
names(inspection_grades_woyear)[names(inspection_grades_woyear)=="key"] <- "grade"
names(inspection_grades_woyear)[names(inspection_grades_woyear)==""] <- "`Unknown"
inspection_grades_woyear <- inspection_grades_woyear %>% gather(key, value, -BORO,-grade)
RelFreq<-function(m){
((m )/sum(m))
}
inspection_grades_woyear<-inspection_grades_woyear %>% group_by(BORO,grade) %>%
mutate(percentage = (value/sum(value))*100)
ggplot(inspection_grades_woyear, aes(BORO, percentage ,fill= key)) +
geom_bar(stat="identity", position = "dodge") +
ggtitle('%Grade Distribution across boroughs') +
labs(x = "Borough", y ="Percentage") + guides(fill=guide_legend(title="Grade")) + theme(plot.title = element_text(size = 25, face = "bold"))

We initially hypothesized that we would see a pattern in grade distribution by borough, however, the plot shows us that grade distributions are almost the same regardless of borough.
inspection_grades_year<-inspection_grades%>% mutate(year=factor(as.numeric(format(INSPECTION.DATE , '%Y'))))
inspection_grades_year<-inspection_grades_year%>% select(-INSPECTION.DATE)
inspection_grades_year <- inspection_grades_year %>% gather(key, value, -BORO,-year) %>% group_by(BORO,year, key, value) %>%
tally %>% spread(value, n, fill = 0)# %>% gather(blah, -BORO, -key) #summarize(aprop = A/(A+B+C+))
names(inspection_grades_year)[names(inspection_grades_year)=="key"] <- "grade"
names(inspection_grades_year)[names(inspection_grades_year)==""] <- "`Unknown"
inspection_grades_year <- inspection_grades_year %>% gather(key, value, -BORO,-grade,-year)
RelFreq<-function(m){
((m )/sum(m))
}
inspection_grades_year<-inspection_grades_year %>% group_by(BORO,grade,year) %>%
mutate(percentage = (value/sum(value))*100)
ggplot(inspection_grades_year, aes(BORO, percentage ,fill= key)) +
geom_bar(stat="identity", position = "dodge") +facet_wrap(~year,nrow=2,ncol=3)+
guides(fill=guide_legend(title="Grade"))+
ggtitle("%Grade Distribution by Borough and Year")+ theme(plot.title = element_text(size = 25, face = "bold"))

Adding year to this analysis showed us an increase in the proportian of As in Staten Island in 2015 but seemed consistent throughout the rest of the plot.
We decided that borough may be too general and thus looked at grade distribution by zip code across the various years. We used a heat map to do so.
library(viridis)
nonYearDataForHeatMap<-ViolationsData %>% select(GRADE,ZIPCODE)
nonYearDataForHeatMap <- nonYearDataForHeatMap %>% group_by(GRADE,ZIPCODE) %>% tally
RelFreq<-function(m){
((m )/sum(m))
}
nonYearDataForHeatMap<- nonYearDataForHeatMap %>% group_by(ZIPCODE)%>%
mutate(percentage = (n/sum(n))*100)
ggplot(nonYearDataForHeatMap, aes(GRADE,
ZIPCODE, fill = percentage)) +
geom_tile() +
scale_fill_viridis() +
ggtitle("Percentage Grade Distribution by Zipcode\n ")+ylab("Zip Code") + theme(plot.title = element_text(size = 35),
axis.text.x = element_text(colour="grey20",size=15,angle=0,hjust=.5,
vjust=.5,face="plain"),
axis.text.y = element_text(colour="grey20",size=10,angle=0,hjust=1,
vjust=0,face="plain"),
axis.title.x = element_text(colour="grey20",size=25,angle=0,hjust=.5,
vjust=0,face="plain"),
axis.title.y = element_text(colour="grey20",size=30,angle=90,hjust=.5,
vjust=.5,face="plain"),
legend.title = element_text(size=20),
legend.text=element_text(size=20), legend.key.size = unit(1, 'in'))

It is interesting to note that missing grades are probably the most probable in general. There are some zip codes with almost no missing grades. The restuarants in those same zip codes seem to mostly have all A grades. Another interesting point is 1 zip code which has all Not Yet Graded grades. In general missing grades and grades of an A seem the most common. This is followed by grades of a B.
The next part of our analysis was to look at the average scores of each cuisine. With this information, we can help consumers see what kinds of establishments have the best and worst scores on average. This in term can help a consumer choose a type of cuisine when they are hungry.
average_scores <- ViolationsData %>% select(-CAMIS, -DBA, -BUILDING, -STREET, -ZIPCODE,
-PHONE, -INSPECTION.DATE, -ACTION,
-VIOLATION.CODE, -VIOLATION.DESCRIPTION,
-CRITICAL.FLAG, -GRADE, -GRADE.DATE,
-RECORD.DATE, -INSPECTION.TYPE)
average_cuisine <- average_scores %>% group_by(CUISINE.DESCRIPTION) %>% na.omit %>%
dplyr::summarize(average_score = mean(SCORE))
average_cuisine <- arrange(average_cuisine, -average_score)
ggplot(average_cuisine, aes(reorder(x = CUISINE.DESCRIPTION, --average_score), average_score,fill="Blue")) + geom_bar(stat='identity') + coord_flip() + theme(legend.position = 'none')+ggtitle("Average Scores Across Cuisines")+xlab("Cuisine Description")+ylab("Average Score")+geom_text(aes(label = sprintf("%.2f", average_score)),position=position_stack(vjust=0.5),vjust = 0.5, size = 3) + theme(plot.title = element_text(size = 25),
axis.title.x = element_text(colour="grey20",size=20,angle=0,hjust=.5,
vjust=0,face="plain"),
axis.title.y = element_text(colour="grey20",size=20,angle=90,hjust=.5,
vjust=.5,face="plain"))

worst10 <- average_cuisine[1:10,]
ggplot(worst10, aes(reorder(x = CUISINE.DESCRIPTION, --average_score), average_score, fill = CUISINE.DESCRIPTION)) + geom_bar(stat='identity') + coord_flip() + theme(legend.position = 'none')+ggtitle("Average Score of Worst 10 cuisines")+xlab("Cuisine Description")+ylab("Average Score")+geom_text(aes(label = sprintf("%.2f", average_score)),position=position_stack(vjust=0.5))

n <- nrow(average_cuisine)
best10 <- average_cuisine[(n- 10):n,]
best10 <- best10[order(best10$average_score),]
ggplot(best10, aes(reorder(x = CUISINE.DESCRIPTION, -average_score), average_score, fill = CUISINE.DESCRIPTION)) + geom_bar(stat='identity') + coord_flip() + theme(legend.position = 'none')+ggtitle("Average Score of top 10 cuisines")+xlab("Cuisine Description")+ylab("Average Score")+geom_text(aes(label = sprintf("%.2f", average_score)),position = position_dodge(width = 1),#position=position_stack(vjust=0.5)
vjust = 0.5, size = 4)

It is interesting that the mysterious “not applicable”" cuisine is one of the best!
In this next plot, we wanted to see if the average score significantly differed by Borough.
average_borough <- average_scores %>% group_by(BORO) %>% na.omit %>%
dplyr::summarize(average_score = mean(SCORE))
ggplot(average_borough, aes(reorder(x = BORO, --average_score), average_score, fill = BORO)) + geom_bar(stat='identity') + theme(legend.position = 'none')+ggtitle("Average Score across boroughs")+xlab("Borough")+ylab("Average Score")+geom_text(aes(label = sprintf("%.2f", average_score)),position = position_dodge(width = 1),
vjust = -0.5, size = 3)

Although we see a slight difference, the boroughs have approximately the same average score. Staten Island may be the one exception. We also faceted by year to see if that made a difference, but the results were essentially the same as in the plot above.
So far we looked at grades and scores but not the actual violations. Whare are the top violations restaurants usually face?
violations<- ViolationsData %>% select(-CAMIS, -DBA, -BUILDING, -STREET, -ZIPCODE,
-PHONE, -INSPECTION.DATE, -ACTION,
-VIOLATION.CODE,
-CRITICAL.FLAG, -GRADE, -GRADE.DATE,
-RECORD.DATE, -INSPECTION.TYPE)
vs <- violations %>% group_by(VIOLATION.DESCRIPTION) %>% na.omit %>%
dplyr::summarize(count = n())
vs <- arrange(vs, -count)
topviolations <- vs[1:10,]
library(stringr)
topviolations$viol = str_wrap(topviolations$VIOLATION.DESCRIPTION, width = 15)
ggplot(topviolations, aes(reorder(viol, -count), count,fill=viol)) + geom_bar(stat='identity') +
theme(legend.position = 'none')+ggtitle("Top 10 violations \n")+xlab("Violation description")+ylab("count")+geom_text(aes(label = sprintf("%.0f", count)),
position = position_dodge(width = 1), vjust = -0.5, size = 7) + theme(plot.title = element_text(size = 40, face = "bold"),
axis.text.x = element_text(colour="grey20",size=20,angle=0,hjust=.5,
vjust=.5,face="plain"),
axis.text.y = element_text(colour="grey20",size=30,angle=0,hjust=1,
vjust=0,face="plain"),
axis.title.x = element_text(colour="grey20",size=30,angle=0,hjust=.5,
vjust=0,face="plain"),
axis.title.y = element_text(colour="grey20",size=30,angle=90,hjust=.5,
vjust=.5,face="plain"))

We also hypothesized that the type of inspections would generally vary by Borough but even this was mostly consistent.
library(viridis)
mos<- ViolationsData %>% select(-CAMIS, -DBA, -BUILDING, -STREET, -ZIPCODE,
-PHONE, -ACTION,
-VIOLATION.CODE,
-CRITICAL.FLAG, -GRADE, -GRADE.DATE,
-RECORD.DATE, -SCORE, -CUISINE.DESCRIPTION, -VIOLATION.DESCRIPTION)
mos$year <- factor(as.numeric( format(mos$INSPECTION.DATE , '%Y')))
mos <- mos %>% select(-INSPECTION.DATE)
average_mos <- mos %>% group_by(BORO, year, INSPECTION.TYPE) %>% tally %>%
group_by(BORO, year) %>%
mutate(percentage = n / sum(n))
#average_cuisine <- arrange(average_cuisine, -average_score)
library(vcd)
average_mos <- average_mos %>% select(-n)
ggplot(average_mos, aes(BORO,
INSPECTION.TYPE, fill = percentage)) +
geom_tile() +
scale_fill_viridis() +
#facet_wrap(~BORO)
ggtitle("Average Violation Score by Zip Code\n ")+ xlab('Borough') +
theme(plot.title = element_text(size = 30, face = "bold"),
axis.text.x = element_text(colour="grey20",size=20,angle=0,hjust=.5,
vjust=.5,face="plain"),
axis.text.y = element_text(colour="grey20",size=15,angle=0,hjust=1,
vjust=0,face="plain"),
axis.title.x = element_text(colour="grey20",size=25,angle=0,hjust=.5,
vjust=0,face="plain"),
axis.title.y = element_text(colour="grey20",size=25,angle=90,hjust=.5,
vjust=.5,face="plain"),
legend.title = element_text(size=30),
legend.text=element_text(size=20), legend.key.size = unit(1, 'in'))

One thing we noticed was that Staten island has the least Cycle Inspection/Initial Inspection. Maybe they were opening up the least new restuarants. They also had the most cycle inspection/re-inspection percentage. As we’ll see in the maps below, those reinspections may have helped restaurants in staten island improve their grades and scores.
One factor of our data set we haven’t discussed too much is the Critical flag, saying whether or not a violation is critical. Once again, we assumed that over the years and across different boroughs, there would be some pattern in critical violations. As can be inferred from the following plot, there is not.
CriticalityData<- ViolationsData %>% select(BORO,INSPECTION.DATE,CRITICAL.FLAG) %>% na.omit()
CriticalityData$year<-factor(as.numeric( format(CriticalityData$INSPECTION.DATE , '%Y')))
#CriticalityData <- CriticalityData %>%select(-INSPECTION.DATE)
CriticalityData <- CriticalityData %>%select(-INSPECTION.DATE) %>% gather(key, value, -BORO, -year) %>% group_by(BORO, year,key,value) %>% tally %>% spread(value, n, fill = 0)
names(CriticalityData)[5] <- "NotApplicable"
names(CriticalityData)[6] <- "NonCritical"
CriticalityDataPercentage<-CriticalityData %>% summarize(criticalPercent = Critical/(Critical+NotApplicable+NonCritical), NotApplicablePercent = NotApplicable/(Critical+NotApplicable+NonCritical), NonCriticalPercent = NonCritical/(Critical+NotApplicable+NonCritical))#
names(CriticalityDataPercentage)[4] <- "Critical"
names(CriticalityDataPercentage)[5] <- "NotApplicable"
names(CriticalityDataPercentage)[6] <- "NonCritical"
CriticalityDataPercentage<-CriticalityDataPercentage%>% gather(key1, value, -BORO, -year,-key)
ggplot(CriticalityDataPercentage, aes(BORO, value, fill = key1)) +
geom_bar(stat="identity", position = "dodge") +
scale_fill_brewer(palette = "Set1")+ xlab("BOROUGH")+ylab("CRITICALITY PERCENTAGES") +theme(axis.text.x = element_text(angle = 45, hjust = 1))+ ggtitle("Grouped barchart of grade frequency in each cuisine category \n when there was a violation reported")+facet_wrap(~year,nrow=2,ncol=3)+guides(fill=guide_legend(title="Criticality \n category"))

We attempted to further analyze the critical flag but we learned that the critical flag did not have too much of an impact on grade or scores. There was a lot of data with a grade of A but a Critical flag while others with a very high score by no critical flag.
VISUALISING DATA WITH MAPS
For the remainder of the analysis, we will be working with Tableau. We chose Tableau because we wanted to plot elegent maps. Tableau provides a simpler and more elegent way to do so than in R.
- Please note that there is a tutorial for deriving maps from generated datset in Tableau in the github repository as ChoroplethMaps.html under the “FinalReport” folder in the Github Repository. It was created by our very own Lakshya Garg.
The code chunks will generate the data that we upload to Tableau. In the following analysis, we explore the proportion of A grades based on neighborhoods over the years.
#####GENERATE GRADE PROPOERTION DATASET BY YEAR FOR TABLEAU PLOTTING
zipdata<- ViolationsData %>% select(-CAMIS, -DBA, -BUILDING, -STREET,
-PHONE, -ACTION,
-VIOLATION.CODE,
-CRITICAL.FLAG, -SCORE, -GRADE.DATE,
-RECORD.DATE, -INSPECTION.TYPE, -VIOLATION.DESCRIPTION, -CUISINE.DESCRIPTION, -BORO) %>% na.omit()
zipdata$year<-factor(as.numeric( format(zipdata$INSPECTION.DATE , '%Y')))
zipdataGradePercentage <- zipdata %>%select(-INSPECTION.DATE) %>%gather(key, value, -ZIPCODE, -year) %>% group_by(ZIPCODE, year, key, value) %>%
tally %>% spread(value, n, fill = 0) %>% summarize(aprop = A/(A+B+C), bprop = B/(A+B+C), cprop = C/(A+B+C) )
# ggplot(zipdataGradePercentage, aes(reorder(x = ZIPCODE, --aprop), aprop)) + geom_bar(stat='identity') +
# coord_flip() + facet_wrap(~year)
# theme( axis.text = element_text(size = 3))
PROPORTIONS OF A GRADES ACROSS THE YEARS
Over the years, the proportion of A’s has increased, as represented by the darker red shading of the map. It is too early to study 2017 in depth due to the limited number of inspections so far. Note that 2017 data maps are only for the first quarter and are likely to change.
knitr::include_graphics('Aprop2013.png')

knitr::include_graphics('Aprop2014.png')

knitr::include_graphics('Aprop2015.png')

knitr::include_graphics('Aprop2016.png')

knitr::include_graphics('Aprop2017.png')

PROPORTIONS OF B GRADES ACROSS THE YEARS
Let’s look at how the proportion of B’s change. We can see that over the years, there seem to be less B’s which makes sense since over the years we have more grades of an A. Note that 2017 data maps are only for the first quarter and are likely to change.
knitr::include_graphics('Bprop1.png')

knitr::include_graphics('Bprop2.png')

knitr::include_graphics('Bprop3.png')

knitr::include_graphics('Bprop4.png')

knitr::include_graphics('Bprop5.png')

AVERAGE SCORES BY ZIPCODE OVER THE YEARS
Let’s look at the average scores by neighborhood. We have already done so by cuisine. Over the years, we have a lower Average Score. These NYC inspections must be prompting resturants to improve their facilities and follow regulations!
Note that 2017 data maps are only for the first quarter and are likely to change.
knitr::include_graphics('AvgScore2013.png')

knitr::include_graphics('AvgScore2014.png')

knitr::include_graphics('AvgScore2015.png')

knitr::include_graphics('AvgScore2016.png')

knitr::include_graphics('AvgScore2017.png')

AVERAGE RE-INSPECTIONS OVER THE YEARS
We decided to see which areas had the highest average number of reinspections. Maybe this can explain the better scores and grades over time. Interestingly enough, the areas with the most reinspections seem to be the ones in which the grades and scores improved. The system of reinspections must be working!
Note that 2017 data maps are only for the first quarter and are likely to change.
### DATA GENERATION
library(stringr)
reinspect <- ViolationsData %>% select(-CAMIS, -DBA, -BUILDING, -STREET, -CUISINE.DESCRIPTION, -BORO, -SCORE,
-PHONE, INSPECTION.DATE, -ACTION,
-VIOLATION.CODE,
-CRITICAL.FLAG, -GRADE, -GRADE.DATE,
-RECORD.DATE)
reinspect$year<-factor(as.numeric( format(reinspect$INSPECTION.DATE , '%Y')))
#inspection_types <- INSPECTION.TYPE
reinspect <- reinspect %>%select(-INSPECTION.DATE) %>% na.omit %>% filter(str_detect(INSPECTION.TYPE, "Re-inspection"))%>%group_by(VIOLATION.DESCRIPTION, year, ZIPCODE ) %>% tally# summarise(re = sum(str_count(reinspect$INSPECTION.TYPE, "Re-inspection")))
knitr::include_graphics('AvgReinspect2013.png')

knitr::include_graphics('AvgReinspect2014.png')

knitr::include_graphics('AvgReinspect2015.png')

knitr::include_graphics('AvgReinspect2016.png')

knitr::include_graphics('AvgReinspect2017.png')

LS0tCnRpdGxlOiAiVG8gRWF0IE9yIE5vdCBUbyBFYXQ/IgphdXRob3I6ICJKb25hdGhhbiBHYWxzdXJrYXIgLSBqZmcyMTUwIHwgTGFrc2h5YSBHYXJnIC0gbGcyOTA2IgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDogZGVmYXVsdAogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKLS0tCiMjIEludHJvZHVjdGlvbgoKSW4gb25lIG9mIHRoZSBncmVhdGVzdCBjaXRpZXMgaW4gdGhlIHdvcmxkLCBOWUMsIHdlIGhhdmUgYW4gYWJ1bmRhbnQgYW1vdW50IG9mIG9wdGlvbnMgdG8gY2hvb3NlIGZyb20gd2hlbiBpdCBjb21lcyB0byB3aGVyZSB3ZSBlYXQsIHdoZXRoZXIgd2UgYXJlIGxvb2tpbmcgZm9yIGZpbmUgZGluaW5nLCBmYXN0IGZvb2QsIG9yIHNvbWV0aGluZyBpbiBiZXR3ZWVuLiBUaGUgY3Vpc2luZSBjaG9pY2VzIHNlZW0ganVzdCBhcyBlbmRsZXNzLiBJcyB0aGVyZSBhIGdvb2Qgd2F5IHRvIGhlbHAgY2hvb3NlIGEgcmVzdGF1cmFudCB0byBlYXQgaW4gb3IgYSBnZW5lcmFsIGxvY2F0aW9uPyBBbHRob3VnaCBub3QgYW4gZWFzeSB0YXNrLCBvbmUgdGhpbmcgd2UgY2FuIGFsbCBhZ3JlZSBvbiBpcyB0aGF0IG5vYm9keSB3YW50cyB0byBlYXQgaW4gYSByZXN0YXVyYW50IHJpZGRlbiB3aXRoIGhlYWx0aCB2aW9sYXRpb25zLiBJbiBvdXIgcHJvamVjdCwgd2Ugd2lsbCBleHBsb3JlIGFuZCBhbmFseXplIE5ZQ+KAmXMgcmVzdGF1cmFudCBpbnNwZWN0aW9uIHJlc3VsdHMgZnJvbSAyMDEzLTIwMTcgb2YgdGhlIGZpdmUgYm9yb3VnaHMuCgpXZSBhcmUgaW50ZXJlc3RlZCBpbiBhbnN3ZXJpbmc6CgoxLiBXaGljaCBjdWlzaW5lcyBoYXZlIHRoZSBsZWFzdCBhbmQgbW9zdCB2aW9sYXRpb25zIGFsb25nIHdpdGggdGhlaXIgYXNzb2NpYXRlZCBzY29yZT8KCjIuIFdoYXQgcGFydHMgb2YgTllDIGhhdmUgdGhlIGxlYXN0IGFuZCBtb3N0IHZpb2xhdGlvbnM/CgozLiBXZSBoeXBvdGhlc2l6ZSB0aGF0IGxvY2F0aW9uIGlzIGhpZ2hseSBhc3NvY2lhdGVkIHdpdGggaW5zcGVjdGlvbiBncmFkZSBhbmQgc28gd2Ugd2lsbCBiZSBzZWFyY2hpbmcgZm9yIHBhdHRlcm5zIGJldHdlZW4gdGhlc2UgdmFyaWFibGVzLgoKNC4gV2UgYXJlIGFsc28gaW50ZXJlc3RlZCBpbiBzZWVpbmcgaG93IGluc3BlY3Rpb24gZ3JhZGUgYW5kIHNjb3JlIGNoYW5nZXMgb3ZlciB0aW1lICh5ZWFycykgYmFzZWQgdXBvbiBjdWlzaW5lIGFuZCBsb2NhdGlvbi4KCjUuIEEgZGVzY3JpcHRpb24gb2YgdmlvbGF0aW9ucyBpcyBhbHNvIHByb3ZpZGVkIGluIHRoZSBkYXRhIGFuZCB3ZSB3b3VsZCBsaWtlIHRvIGJldHRlciB1bmRlcnN0YW5kIHRoZSBjb21tb24gY2F1c2VzIG9mIHRob3NlIHZpb2xhdGlvbnMgYmFzZWQgdXBvbiB0aGUgZGVzY3JpcHRpb24uCgo2LiBJcyB0aGVyZSBhIHBhdHRlcm4vdHJlbmQgaW4gdmlvbGF0aW9ucy9pbnNwZWN0aW9uIHNjb3JlL2dyYWRlIGJhc2VkIHVwb24gcmVzdGF1cmFudCBjaGFpbnM/CgpXZSBmb3VuZCB0aGlzIGRhdGEgc2V0IGJ5IGV4cGxvcmluZyBOWUMgb3BlbiBkYXRhIHNldHMuIE91ciBsb3ZlIGZvciBmb29kIGFuZCBoZWFsdGggbWFkZSB0aGlzIGEgZ3JlYXQgb3B0aW9uLiBPbmUgb2Ygb3VyIHRlYW0gbWVtYmVycyB3aG8gcmVjZW50bHkgbW92ZWQgdG8gTllDIGlzIGhpZ2hseSBzZWxlY3RpdmUgYWJvdXQgdGhlIGZvb2Qgc2hlIGVhdHMgZHVlIHRvIGhlciByYXJlIGhlYWx0aCBjb25kaXRpb24gYW5kIGhlbmNlLCBoYXZpbmcgdGhlIGtpbmRzIG9mIHF1ZXN0aW9ucyBtZW50aW9uZWQgYWJvdmUgYW5zd2VyZWQgY2FuIHByb3ZlIHRvIGJlIGEgZ3JlYXQgYXNzZXQgdG8gYm90aCBoZXIgYW5kIG90aGVycyBzdWZmZXJpbmcgZnJvbSBoZWFsdGggY29uZGl0aW9ucyBvciB3aG8gbWF5IGp1c3QgYmUgcGlja3kgZWF0ZXJzISBUaGUgZGF0YSBjYW4gYmUgZm91bmQgYW5kIGRvd25sb2FkZWQgaGVyZTogaHR0cHM6Ly9kYXRhLmNpdHlvZm5ld3lvcmsudXMvSGVhbHRoL0RPSE1ILU5ldy1Zb3JrLUNpdHktUmVzdGF1cmFudC1JbnNwZWN0aW9uLVJlc3VsdHMveHg2Ny1rdDU5CgpUbyBkb3dubG9hZCwgY2xpY2sgdGhlIGV4cG9ydCBidXR0b24gb24gdGhlIHJpZ2h0IC0+IERvd25sb2FkIGFzIC0+IGNob29zZSB5b3VyIGZvcm1hdC4gRm9yIHRoaXMgYXNzaWduZW1lbnQgd2UgdXNlZCB0aGUgQ1NWIGZvcm1hdC4KCiMjIFRlYW0KCiMjIyMjIFRlYW0gTWVtYmVyczoKKyBKb25hdGhhbiBHYWxzdXJrYXIKKyBMYWtzaHlhIEdhcmcKCiMjIyMjIFRhc2sgRGlzdHJpYnV0aW9uCkdldCB0YWJsZSBmb3JtYXQgZm9yIHRoaXMKYGBge3J9CmxpYnJhcnkoa25pdHIpClRhc2tEaXN0cmlidXRpb24gPC0gcmVhZC5jc3YoZmlsZT0iVGFza0Rpc3RyaWJ1dGlvbi5jc3YiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgaGVhZGVyPVRSVUUsIHNlcD0iLCIsYXMuaXM9VFJVRSkKa2FibGUoVGFza0Rpc3RyaWJ1dGlvbiApCmBgYAoKIyMgQW5hbHlzaXMgb2YgRGF0YSBRdWFsaXR5ClRvIGJlZ2luIG91ciBhbmFseXNpcyBvZiBkYXRhIHF1YWxpdHksIGxldCdzIGxvYWQgb3VyIGRhdGEuCmBgYHtyfQpWaW9sYXRpb25zRGF0YSA8LSByZWFkLmNzdihmaWxlPSJpbnNwZWN0aW9uLmNzdiIsIGhlYWRlcj1UUlVFLCBzZXA9IiwiLCBhcy5pcz1UUlVFKQpgYGAKCiMjIyBEYXRhc2V0IERlc2NyaXB0aW9uCmBgYHtyfQpEYXRhc2V0RGVzY3JpcHRpb24gPC0gcmVhZC5jc3YoZmlsZT0iRGVzY3JpcHRpb25EYXRhc2V0LmNzdiIsIGhlYWRlcj1UUlVFLCBzZXA9IiwiLCBhcy5pcz1UUlVFKQprYWJsZShEYXRhc2V0RGVzY3JpcHRpb24gKQpgYGAKCkluIG9yZGVyIHRvIG1vcmUgZWFzaWx5IHdvcmsgd2l0aCBvdXIgZGF0YSBsZXQncyBlbnN1cmUgdGhhdCBldmVyeSBkYXRlIGlzIGluIGEgZGF0ZSBmb3JtYXQgcmF0aGVyIHRoYW4gYSBzdHJpbmcgYW5kIGV2ZXJ5IHN0cmluZyBpcyBhIGZhY3RvciB2YXJpYWJsZS4KYGBge3IgbWVzc2FnZT1GQUxTRX0KCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkodGlkeXIpCiMjRGF0ZSBjb252ZXJzaW9uClZpb2xhdGlvbnNEYXRhIDwtIFZpb2xhdGlvbnNEYXRhICU+JQogIG11dGF0ZShJTlNQRUNUSU9OLkRBVEU9IGFzLkRhdGUoSU5TUEVDVElPTi5EQVRFLCBmb3JtYXQ9ICIlbS8lZC8lWSIpKSU+JQogIG11dGF0ZShHUkFERS5EQVRFPSBhcy5EYXRlKEdSQURFLkRBVEUsIGZvcm1hdD0gIiVtLyVkLyVZIikpJT4lCiAgbXV0YXRlKFJFQ09SRC5EQVRFPSBhcy5EYXRlKFJFQ09SRC5EQVRFLCBmb3JtYXQ9ICIlbS8lZC8lWSIpKQojI0ZhY3RvciBjb252ZXJzaW9uClZpb2xhdGlvbnNEYXRhIDwtIFZpb2xhdGlvbnNEYXRhICU+JQogIG11dGF0ZShDVUlTSU5FLkRFU0NSSVBUSU9OPSBhcy5mYWN0b3IoQ1VJU0lORS5ERVNDUklQVElPTikpJT4lCiAgbXV0YXRlKEJPUk89IGFzLmZhY3RvcihCT1JPKSklPiUKICBtdXRhdGUoVklPTEFUSU9OLkNPREU9IGFzLmZhY3RvcihWSU9MQVRJT04uQ09ERSkpJT4lCiAgbXV0YXRlKENSSVRJQ0FMLkZMQUc9IGFzLmZhY3RvcihDUklUSUNBTC5GTEFHKSklPiUKICBtdXRhdGUoR1JBREU9IGFzLmZhY3RvcihHUkFERSkpJT4lCiAgbXV0YXRlKElOU1BFQ1RJT04uVFlQRT0gYXMuZmFjdG9yKElOU1BFQ1RJT04uVFlQRSkpCgpzdW1tYXJpemUgPC0gZHBseXI6OnN1bW1hcml6ZQptdXRhdGUgPC0gZHBseXI6Om11dGF0ZQpgYGAKCgpNYW55IG9mIHRoZSBxdWVzdGlvbnMgd2UgYXJlIGludGVyZXN0ZWQgaW4gYW5zd2VyaW5nIGludm9sdmUgdHJlbmRzIGFjcm9zcyByZXN0dWFyYW50IGxvY2F0aW9ucy4gV2UgZmlyc3QgY2hlY2tlZCB0byBzZWUgdGhlIG51bWJlciBvZiByZXN0dWFyYW50IGluc3BlY3Rpb25zIGJ5IGJvcm91Z2guIEZyb20gdGhlIHBsb3QgYmVsb3csIHdlIG5vdGljZWQgdGhhdCB0aGVyZSB3ZXJlIGEgbnVtYmVyIG9mIGluc3BlY3Rpb25zIGluIHdoaWNoIHRoZSBCb3JvdWdoIGluZm9ybWF0aW9uIHdhcyBtaXNzaW5nIGFuZCB3b24ndCBoZWxwIG91ciBhbmFseXNpcy4KYGBge3J9CmxpYnJhcnkoZ2dwbG90MikKYm9yb3VnaFBsb3QgPC0gZ2dwbG90KFZpb2xhdGlvbnNEYXRhLCBhZXMoQk9STywgZmlsbD1CT1JPKSkKYm9yb3VnaFBsb3QgKyBnZW9tX2JhcigpKyB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSArCiAgZ2d0aXRsZSgnSW5zcGVjdGlvbiBDb3VudCBieSBCb3JvdWdoJykgKyAKICBsYWJzKHggPSAiQm9yb3VnaCIsIHkgPSJOdW1iZXIgb2YgSW5zcGVjdGlvbnMiKQpgYGAKCkFub3RoZXIgbWFpbiBmZWF0dXJlIG9mIG91ciBkYXRhIHNldCBpcyB0aGUgaW5zcGVjdGlvbiB5ZWFyIHNpbmNlIHdlIHdpc2ggdG8gZXhwbG9yZSBwYXR0ZXJzIGluIGluc3BlY3Rpb24gZ3JhZGVzL3Njb3JlcyBvdmVyIHRoZSB5ZWFycy4gRnJvbSB0aGUgcGxvdCBiZWxvdywgd2Ugbm90aWNlZCB0aGF0IHRoZXJlIGlzIGFsbW9zdCBubyBpbnNwZWN0aW9uIGRhdGEgYmVmb3JlIDIwMTMgYW5kIHN1cnByaXNpbmdseSBtb3JlIGluc3BlY3Rpb24gZGF0YSBpbiAxOTAwIHRoYW4gMjAxMiBhbmQgMjAxMS4gV2UgZGVjaWRlZCB0byBvbmx5IHdvcmsgd2l0aCBkYXRhIGZyb20gMjAxMyBhbmQgdXAuIEl0IGlzIGltcG9ydGFudCB0byBub3RlIHRoYXQgdGhlIG51bWJlciBvZiBpbnNwZWN0aW9ucyBmb3IgMjAxNyBpcyBsb3cgc2luY2UgdGhlIDIwMTcgZGF0YSBpcyBvbmx5IGF2YWlsYWJsZSBmcm9tIEphbnVhcnkgLSBNYXJjaC4KYGBge3J9CnZpb2xhdGlvblllYXJzUGxvdCA8LSBnZ3Bsb3QoVmlvbGF0aW9uc0RhdGEsIGFlcyhmYWN0b3IoYXMubnVtZXJpYyhmb3JtYXQoSU5TUEVDVElPTi5EQVRFLCAnJVknKSkpLCBmaWxsPSJSZWQiKSkKdmlvbGF0aW9uWWVhcnNQbG90ICsgZ2VvbV9iYXIoKStjb29yZF9mbGlwKCkrIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpICt4bGFiKCJJbnNwZWN0aW9uIFllYXIiKSt5bGFiKCJJbnNwZWN0aW9uIENvdW50cyIpICsgZ2d0aXRsZSgiSW5zcGVjdGlvbiBDb3VudCBieSBZZWFyIikKYGBgCgpBbm90aGVyIGNydWNpYWwgZmVhdHVyZSBvZiBvdXIgZGF0YSBzZXQgaXMgZ3JhZGUgYSByZXN0YXVyYW50IHJlY2VpdmVkIGFmdGVyIGluc3BlY3Rpb24uIFdlIGRlY2lkZWQgdG8gcGxvdCBhIHN0YWNrZWQgYmFyIGNoYXJ0IGZvciB0byBzZWUgdGhlIGNvdW50IG9mIGVhY2ggdHlwZSBvZiBncmFkZSBmb3IgZXZlcnkgY3Vpc2luZS4gV2UgdXNlZCBhIHN0YWNrZWQgYmFyIGNoYXJ0IGJlY2F1c2Ugd2Ugd2FudGVkIHRvIHF1aWNrbHkgYXNzZXNzIHRoZSBtYWduaXR1ZGUgbWlzc2luZyB3aXRob3V0IHRha2luZyB1cCBleHRyYSByb29tLiBGcm9tIHRoZSBwbG90IGJlbG93LCBpdCB3YXMgc2hvY2tpbmcgdG8gc2VlIHRoYXQgd2UgZ2VuZXJhbGx5IGhhZCBtb3JlIG1pc3NpbmcgZ3JhZGVzIHRoYW4gZ3JhZGVzLiBUaGlzIHdhcyB0cnVlIHJlZ2FyZGxzcyBvZiBjdWlzaW5lLiBJdCB3YXMgYWxzbyBpbnRlcmVzdGluZyB0aGF0IHRoZSBncmFkZXMgd2VyZSBwdXJlbHkgbWlzc2luZyBhbmQgbm90IGNhdGVnb3JpemVkIGFzICJOb3QgWWV0IEdyYWRlZCIuCmBgYHtyLGZpZy5oZWlnaHQ9MTd9CmdncGxvdChWaW9sYXRpb25zRGF0YSwgYWVzKENVSVNJTkUuREVTQ1JJUFRJT04sIGZpbGwgPSBHUkFERSkpICsgZ2VvbV9iYXIoKSArIAogIGNvb3JkX2ZsaXAoKSArIGdndGl0bGUoIlN0YWNrZWQgQmFyIENoYXJ0IG9mIEdyYWRlIERpc3RyaWJ1dGlvbnMgQWNyb3NzIEN1aXNpbmVzIikgKwogIHhsYWIoJ0N1aXNpbmUnKSArIHlsYWIoJ0NvdW50JykgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDcwLCBmYWNlID0gImJvbGQiKSwgCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoY29sb3VyPSJncmV5MjAiLHNpemU9NjAsYW5nbGU9MCxoanVzdD0uNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmp1c3Q9LjUsZmFjZT0icGxhaW4iKSwgCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoY29sb3VyPSJncmV5MjAiLHNpemU9MzAsYW5nbGU9MCxoanVzdD0xLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZqdXN0PTAsZmFjZT0icGxhaW4iKSwgIAogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChjb2xvdXI9ImdyZXkyMCIsc2l6ZT02MCxhbmdsZT0wLGhqdXN0PS41LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2anVzdD0wLGZhY2U9InBsYWluIiksCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KGNvbG91cj0iZ3JleTIwIixzaXplPTUwLGFuZ2xlPTkwLGhqdXN0PS41LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2anVzdD0uNSxmYWNlPSJwbGFpbiIpLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTQwKSwKICAgICAgICBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT00MCksIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMSwgJ2luJykpCmBgYAoKVG8gc3RheSBvbiB0aGUgdG9waWMgb2YgZ3JhZGVzLCBhZnRlciByZXNlYXJjaGluZyB0aGUgbGV0dGVyIGdyYWRpbmcgcHJvZ3JhbSwgd2UgZm91bmQgdGhlIGZvbGxvd2luZyBpbmZvcm1hdGlvbjogCgorIEJsYW5rIEdyYWRlIChSZWQpOiBUaGUgZm9sbG93aW5nIGFyZSBzY29yZWQgYnV0IG5vdCBncmFkZWQuIEZvciBleC4gSW5pdGlhbCBpbnNwZWN0aW9ucyB0aGF0IHJlc3VsdCBpbiBhIHNjb3JlIG9mIDE0IHBvaW50cyBvciBoaWdoZXIsIG1vbml0b3JpbmcgaW5zcGVjdGlvbnMgYXQgYSByZXN0YXVyYW50IHRoYXQgaGFzIHBlcmZvcm1lZCB2ZXJ5IHBvb3JseSBvbiBpdHMgcmUtaW5zcGVjdGlvbi4gVGhlIEhlYWx0aCBEZXBhcnRtZW50IG1heSBjb250aW51ZSB0byBpbnNwZWN0IHRoZSByZXN0YXVyYW50IHJvdWdobHkgb25jZSBhIG1vbnRoIHVudGlsIGl0IHNjb3JlcyBiZWxvdyAyOCBvciB0aGUgRGVwYXJ0bWVudCBjbG9zZXMgaXQgZm9yIHNlcmlvdXMgYW5kIHBlcnNpc3RlbnQgdmlvbGF0aW9ucywgaW5zcGVjdGlvbnMgYXQgbmV3IHJlc3RhdXJhbnRzIG5vdCB5ZXQgb3BlbiB0byB0aGUgcHVibGljLCBhbiBpbnNwZWN0aW9uIGF0IGEgcmVzdGF1cmFudCBzZWVraW5nIHRvIHJlb3BlbiBhZnRlciB0aGUgRGVwYXJ0bWVudCBjbG9zZWQgaXQsIHNvbWUgaW5zcGVjdGlvbnMgaW4gcmVzcG9uc2UgdG8gY29tcGxhaW50cy4KCisgQSBzY29yZSBvZiBsZXNzIHRoYW4gMTQgcG9pbnRzIG9uIGVpdGhlciBpbml0aWFsIG9yIHJlLWluc3BlY3Rpb24gcmVzdWx0cyBpbiBhbiDigJxB4oCdIGdyYWRlCgorIE9uIHJlLWluc3BlY3Rpb24sIGEgc2NvcmUgb2YgMTQtMjcgcG9pbnRzIG1lYW5zIGEgcmVzdGF1cmFudCByZWNlaXZlcyBib3RoIGEg4oCcQuKAnSBncmFkZSBhbmQgYSDigJxHcmFkZSBQZW5kaW5n4oCdIGNhcmQuCgorIE9uIHJlLWluc3BlY3Rpb24sIGEgc2NvcmUgb2YgMjggb3IgbW9yZSBwb2ludHMgbWVhbnMgYSByZXN0YXVyYW50IHJlY2VpdmVzIGJvdGggYSDigJxD4oCdIGdyYWRlIGFuZCBhIOKAnEdyYWRlIFBlbmRpbmfigJ0gY2FyZC4KCisgQm90aCBaIGFuZCBQIHJlcHJlc2VudCBncmFkZSBwZW5kaW5nLCBob3dldmVyIFAgcmVwcmVzZW50cyBhIEdyYWRlIFBlbmRpbmcgaXNzdWVkIG9uIHJlLW9wZW5pbmcgZm9sbG93aW5nIGFuIGluaXRpYWwgaW5zcGVjdGlvbiB0aGF0IHJlc3VsdGVkIGluIGEgY2xvc3VyZS4KCldlIGFsc28gZGlzY292ZXJlZCB0aGF0IG5vdCBldmVyeSBpbnNwZWN0aW9uIGlzICJncmFkYWJsZSIuIEdyYWRhYmxlIGluc3BlY3Rpb25zIGhhdmUgdGhlIGZvbGxvd2luZyBwcm9wZXJ0aWVzOgoKKyBJTlNQRUNUSU9OIFRZUEUgaW4gKEN5Y2xlIEluc3BlY3Rpb24vSW5pdGlhbCBJbnNwZWN0aW9uLCBDeWNsZSBJbnNwZWN0aW9uL1JlLUluc3BlY3Rpb24sIFByZS1QZXJtaXQgKE9wZXJhdGlvbmFsKS9Jbml0aWFsIEluc3BlY3Rpb24sIFByZS1QZXJtaXQgKE9wZXJhdGlvbmFsKS9SZS1JbnNwZWN0aW9uKQoKKyBBQ1RJT04gaW4gKFZpb2xhdGlvbnMgd2VyZSBjaXRlZCBpbiB0aGUgZm9sbG93aW5nIGFyZWEocyksIE5vIHZpb2xhdGlvbnMgd2VyZSByZWNvcmRlZCBhdCB0aGUgdGltZSBvZiB0aGlzIGluc3BlY3Rpb24sIEVzdGFibGlzaG1lbnQgQ2xvc2VkIGJ5IERPSE1IKQoKKyBJTlNQRUNUSU9OIERBVEUgPiBKdWx5IDI2LCAyMDEwCgpUaGlzIGNhbiBwcm9iYWJseSBleHBsYWluIGEgZmFpciBhbW91bnQgb2YgdGhlIG1pc3NpbmcgZ3JhZGUgZGF0YSBvYnNlcnZlZCBpbiBvdXIgcGxvdC4KCkFjY29yZGluZyB0byB0aGUgQUJPVVQgdGhlIGRhdGEgc2V0IHBhZ2U6IFRoZSBTQ09SRSBhbmQgR1JBREUgZmllbGRzIG1heSBiZSBpbmNvbnNpc3RlbnQgd2l0aCBlYWNoIG90aGVyIGJlY2F1c2Ugb2YgbGltaXRhdGlvbnMgb3IgZXJyb3JzIGluIHRoZSBkYXRhIHN5c3RlbXMuIFRoYXQgaXMgdG8gc2F5LCBzY29yZXMgb2YgMC0xMywgMTQtMjcgYW5kIDI4KyBhcmUgbm90IGFsd2F5cyBhY2NvbXBhbmllZCBieSBBLCBCIGFuZCBDIGdyYWRlcywgcmVzcGVjdGl2ZWx5LCB3aGVuIHRoZXkgc2hvdWxkIGJlLiBUaGVyZSBtYXkgYWxzbyBiZSBjYXNlcyB3aGVyZSBhIGdyYWRlIGNhcmQgd2FzIGdpdmVuIG91dCBidXQgYSByZWNvcmQgb2YgdGhhdCBncmFkZSBpc3N1YW5jZSBpcyBtaXNzaW5nIGZyb20gdGhlIGRhdGEgc3lzdGVtLCBhbmQgdGhlcmVmb3JlIG1pc3NpbmcgZnJvbSB0aGlzIGRhdGFzZXQsIGV2ZW4gdGhvdWdoIHRoZSBTQ09SRSBmaWVsZCBpcyBwb3B1bGF0ZWQuICBOb3RlIHRoYXQgd2hlbiBpbml0aWFsIGluc3BlY3Rpb25zIGFyZSBhZGp1ZGljYXRlZCBkb3duIHRvIHRoZSBBIHJhbmdlLCB0aGUgYWJzZW5jZSBvZiBhbiBhY2NvbXBhbnlpbmcgZ3JhZGUgYXNzb2NpYXRlZCB3aXRoIHRoYXQgaW5zcGVjdGlvbiBpcyBjb3JyZWN0LCBiZWNhdXNlIHRoZSBncmFkZSB3b3VsZCBub3QgYmUgYXNzaWduZWQgdW50aWwgdGhlIHJlLWluc3BlY3Rpb24gaXMgcGVyZm9ybWVkLiAKClRvIGdhaW4gc29tZSBmaW5hbCBpbnNpZ2h0IG9uIHRoZSBkYXRhIHF1YWxpdHksIHdlIGRlY2lkZWQgdG8gcGxvdCB0aGUgcmVsYXRpb25zaHAgYmV0d2VlbiB0aGUgbnVtYmVyIG9mIG1pc3Npbmcgc2NvcmVzIGJ5IGdyYWRlIGFuZCBieSB3aGV0aGVyIG9yIG5vdCBhIHZpb2xhdGlvbiB3YXMgcmVwb3J0ZWQuIFdlIHRyYW5zZm9ybWVkIHRoZSBhY3Rpb25zIHRha2VuIGludG8gdGhyZWUgY2F0ZWdvcmllczoKMS4gTm8gdmlvbGF0aW9ucyB3ZXJlIHJlY29yZGVkIGF0IHRoZSB0aW1lIG9mIHRoaXMgaW5zcGVjdGlvbiB0byBObyBWaW9sYXRpb24KMi4gQW55IGFjdGlvbiByZXBvcnRlZCB0byBWaW9sYXRpb24gcmVwb3J0ZWQKMy4gTWlzc2luZyBhY3Rpb25zIHRvIE5BCldlIHRoZW4gY291bnRlZCBpZiB0aGUgc2NvcmUgd2FzIHByb3ZpZGVkIG9yIG5vdC4KCmBgYHtyLGZpZy5oZWlnaHQ9NCwgbWVzc2FnZSA9IEZBTFNFfQpsaWJyYXJ5KHBseXIpCnNjb3JlX2dyYWRlIDwtIFZpb2xhdGlvbnNEYXRhWyAtYygxOjksIDExOjEzLCAxNjoxOCkgXQpzY29yZV9ncmFkZVtzY29yZV9ncmFkZSA9PSAnJ10gPC0gTkEKc2NvcmVfZ3JhZGVfY29tYm9zIDwtIHNjb3JlX2dyYWRlICAlPiUgbXV0YXRlKG1pc3Npbmdfc2NvcmUgPSBpZmVsc2UoaXMubmEoU0NPUkUpLCAieWVzIiwgIm5vIikpCnNjb3JlX2dyYWRlX21pc3NpbmcgPC0gY291bnQoc2NvcmVfZ3JhZGVfY29tYm9zLCBjKCdHUkFERScsICdtaXNzaW5nX3Njb3JlJywgJ0FDVElPTicpKQpzY29yZV9ncmFkZV9taXNzaW5nIDwtIHNjb3JlX2dyYWRlX21pc3NpbmcgJT4lIAogIG11dGF0ZSh2aW9sYXRpb24gPSBpZmVsc2UoQUNUSU9OID09ICdObyB2aW9sYXRpb25zIHdlcmUgcmVjb3JkZWQgYXQgdGhlIHRpbWUgb2YgdGhpcyBpbnNwZWN0aW9uLicsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTm8gdmlvbGF0aW9uIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoaXMubmEoc2NvcmVfZ3JhZGVfbWlzc2luZyRBQ1RJT04pLCBOQSwgIlZpb2xhdGlvbiBSZXBvcnRlZCIpKSkgJT4lCiAgc2VsZWN0KC1jKEFDVElPTikpCmdncGxvdChzY29yZV9ncmFkZV9taXNzaW5nLCBhZXMoeCA9IEdSQURFLCB5ID0gbG9nKGZyZXEpLCBmaWxsID0gbWlzc2luZ19zY29yZSkpICsgCiAgZ2VvbV9iYXIoc3RhdCA9ICdpZGVudGl0eScsIHBvc2l0aW9uID0gJ2RvZGdlJykgKyBmYWNldF93cmFwKH52aW9sYXRpb24pICsgCiAgZ2d0aXRsZSgiR3JhZGUgYW5kIG1pc3Npbmcgc2NvcmUgY29tYmluYXRpb25zIGJ5IHZpb2xhdGlvbiByZXBvcnQiKSArCiAgbGFicyh4ID0gIkdyYWRlIiwgeSA9ICJMb2coRnJlcXVlbmN5KSIpCmBgYAoKT3RoZXIgaW50ZXJlc3RpbmcgaW5zaWdodHMgYnkgZXhwbG9yaW5nIGRhdGEgbWFudWFsbHkgYXJlOgoKMS4gR3JhZGVzIG9mIE5BIHJlcG9ydGVkIGhpZ2ggZnJlcXVlbmN5IG9mIHNjb3JlIGluIGJvdGggTm8gdmlvbGF0aW9uIGFuZCB2aW9sYXRpb24gcmVwb3J0ZWQgY2F0ZWdvcnkuCgoyLiBBdCBmaXJzdCwgaXQgYXBwZWFycyB0aGF0IGhpZ2ggc2NvcmVzIGFyZSByZWxhdGVkIHRvIGxvdyBncmFkZXMgb3IgbmVlZHMgZ3JhZGluZyBidXQgdGhlbiB3ZSBmaW5kIHJlc3RhdXJhbnRzIHdpdGggYSBncmFkZSBvZiBBIHRoYXQgaGFzIHRoZSBzYW1lIHNjb3JlIGFzIGEgcmVzdGF1cmFudCB3aXRoIGEgZ3JhZGUgb2YgQy4KCjMuIEFub3RoZXIgaW5zaWdodCBieSBqdXN0IGxvb2tpbmcgYXQgdGhlIGRhdGEgaXMgd2Ugc3VycHJpc2luZ2x5IHNhdyB0aGF0IHJlc3RhdXJhbnRzIHdpdGggYSBjcml0aWNhbCBmbGFnIHN0aWxsIHJlY2VpdmUgZ3JhZGVzIG9mIEEuCgojIyBFeGVjdXRpdmUgU3VtbWFyeQpOWUMgcHV0cyBhIGxvdCBvZiB0aW1lIGFuZCBtb25leSBpbnRvIGluc3BlY3RpbmcgcmVzdHVhcmFudHMuIFdoeSB3b3VsZCB0aGV5IGdvIHRocm91Z2ggYWxsIHRoaXMgdHJvdWJsZT8gVG8gZW5zdXJlIHF1YWxpdHkgbWVhbHMgYW5kIHNhdGlzZmFjdGlvbiBvZiBOWUMgcmVzaWRlbnRzIG9mIGNvdXJzZSEgSXQgaXMgaW1wb3J0YW50IGZvciByZXN0YXVyYW50cyBhbmQgZXN0YWJsaXNobWVudCB0aGF0IG1lZXQgYXQgbGVhc3QgdGhlIG1pbmltdW0gcmVxdWlyZW1lbnRzIG9mIGhlYWx0aCBhbmQgc2FmZXR5IHJlZ3VsYXRpb25zIGluIG9yZGVyIHRvIHByb21vdGUgbGVzcyBmb29kIHNpY2sgcmVzaWRlbnRzIGFuZCBhIGNsZWFuZXIgTllDLiAKCkhvdyBjYW4gd2UgdGVsbCBpZiB0aGVzZSBpbnNwZWN0aW9ucyBhcmUgYWN0dWFsbHkgd29ya2luZyB0byBwcm9tb3RlIHJlc3R1YXJhbnRzIHRvIG1lZXQgcmVndWxhdGlvbnM/IExldCdzIHRha2UgYSBsb29rIGF0IHRoZSBwcm9wb3J0aW9uIG9mIHNjb3JlcyB0aGF0IHdlcmUgZ3JhZGVkIGFuIEEgaW4gMjAxMyBhbmQgdGhlIHByb3BvcnRpb24gb2Ygc2NvcmVzIHRoYXQgd2VyZSBncmFkZWQgYW4gQSBpbiAyMDE2LiBMZXQncyB2aWV3IHRoaXMgaW5mb3JtYXRpb24gYnkgbG9jYXRpb24gc28gdGhhdCB5b3Uga25vdyB3aGF0IG5laWdoYm9yaG9vZCB0byBjaG9vc2Ugd2hlbiB5b3UncmUgY3JhdmluZyBhIHJlc3RhdXJhbnQuCgpgYGB7ciBlY2hvID0gRkFMU0V9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCdBcHJvcDIwMTMucG5nJykKYGBgCgpgYGB7ciBlY2hvID0gRkFMU0V9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCdBcHJvcDIwMTYucG5nJykKYGBgCgpUaGUgZGFya2VyIHRoZSBzaGFkZSBvZiByZWQsIHRoZSBoaWdoZXIgcHJvcG9ydGlvbiBvZiBBIGdyYWRlcy4gSXQgaXMgY2xlYXIgdGhhdCBvdmVyIHRoZSBsYXN0IDMgeWVhcnMsIHRoZSBwcm9wb3J0aW9uIG9mIHJlc3R1YXJhbnRzIHdpdGggYSBncmFkZSBvZiBhbiBBIGhhcyBpbnNjcmVhc2VkLiBOWUMgaW5zcGVjdGlvbnMgbXVzdCBiZSB3b3JraW5nIHRvIGltcHJvdmUgdGhlIHF1YWxpdHkgb2YgdGhlIHJlc3R1YXJhbnRzIHdlIGVhdCBpbiEgSW4gMjAxMywgaXQgc2VlbXMgdGhhdCB0aGUgdGhlcmUgd2VyZSBvbmx5IGEgZmV3IG5laWdoYm9yaG9vZHMgd2l0aCBhbiBleHRyZW1lbHkgaGlnaCBwcm9wb3J0aW9uIG9mIEEgZ3JhZGVzLiBPbmx5IDMgYXJlYXMgaW4gU3RhdGVuIElzbGFuZCwgMSBpbiBMb25nIElzbGFuZCwgYSBmZXcgaW4gQnJvb2tseW4sIE1hbmhhdHRhbiwgYW5kIHRoZSBCcm9ueC4gSW4gMjAxNiBvbiB0aGUgb3RoZXIgaGFuZCwgdGhlIHByb3BvcnRpb24gb2YgQSBncmFkZXMgaXMgdmVyeSBoaWdoIGFsbW9zdCByZWdhcmRsZXNzIG9mIG5laWdoYm9yaG9vZC4gS2VlcCBpdCB1cCBOWUMgcmVzdHVhcmFudCBpbnNwZWN0aW9ucyEKClRvIHNlZSB0aGlzIGZyb20gYW5vdGhlciBhbmdsZSwgbGV0J3MgbG9vayBhdCB0aGUgYXZlcmFnZSBzY29yZXMgcGVyIG5laWdoYm9yaG9vZCBpbiAyMDEzIGFuZCAyMDE2LiBBdmVyYWdlIHNjb3JlcyB3ZXJlIGJpbm5lZCBpbiB0aGUgbGVnZW5kIHN1Y2ggdGhhdDoKCisgMSBtZWFucyB0aGF0IHRoZSBhdmVyYWdlIHNjb3JlIHdhcyBsZXNzIHRoYW4gMTAsCgorIDIgaWYgdGhlIGF2ZXJhZ2Ugc2NvcmUgd2FzIGJldHdlZW4gMTAgYW5kIDIwLCAKCisgMyBpZiB0aGUgYXZlcmFnZSBzY29yZSB3YXMgYmV0d2VlbiAyMCBhbmQgMzAsCgorIDQgaWYgdGhlIGF2ZXJhZ2Ugc2NvcmUgd2FzIGJldHdlZW4gMzAgYW5kIDQwLAoKKyA1IGlmIGl0IHdhcyBiZXR3ZWVuIGEgNDAgYW5kIDUwLgoKYGBge3IgZWNobyA9IEZBTFNFfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygnQXZnU2NvcmUyMDEzLnBuZycpCmBgYAoKYGBge3IgZWNobyA9IEZBTFNFfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygnQXZnU2NvcmUyMDE2LnBuZycpCmBgYAoKSnVzdCBsb29rIGhvdyBtdWNoIGxpZ2h0ZXIgdGhlIGNvbG9yIG9mIGVhY2ggbmVpZ2hib3Job29kIGdvdCEgTGlnaHRlciBjb2xvcnMgbWVhbiBhIGxvd2VyIGF2ZXJhZ2Ugc2NvcmUsIHdoaWNoIGNvcnJlbGF0ZXMgdG8gbGVzcyB2aW9sYXRpb25zIGFuZCBoZWFsdGhpZXIgZXN0YWJsaXNobWVudHMhCgpXZWxsIG5vdyB3ZSBrbm93IHdoYXQgbmVpZ2hib3Job29kcyB0byBiZSBpbiBmb3IgZXN0YWJsaXNobWVudHMgd2l0aCBsb3cgc2NvcmVzIGFuZCBBIGdyYWRlcywgYnV0IHdoYXQgYXJlIHRoZSBhdmVyYWdlIHNjb3JlcyBiYXNlZCB1cG9uIGN1aXNpbmU/CgpgYGB7ciBlY2hvID0gRkFMU0V9CmxpYnJhcnkoZHBseXIpCmxpYnJhcnkodGlkeXIpCmF2ZXJhZ2Vfc2NvcmVzIDwtIFZpb2xhdGlvbnNEYXRhICU+JSBzZWxlY3QoLUNBTUlTLCAtREJBLCAtQlVJTERJTkcsIC1TVFJFRVQsIC1aSVBDT0RFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAtUEhPTkUsIC1JTlNQRUNUSU9OLkRBVEUsIC1BQ1RJT04sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC1WSU9MQVRJT04uQ09ERSwgLVZJT0xBVElPTi5ERVNDUklQVElPTiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLUNSSVRJQ0FMLkZMQUcsIC1HUkFERSwgLUdSQURFLkRBVEUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC1SRUNPUkQuREFURSwgLUlOU1BFQ1RJT04uVFlQRSkKCmF2ZXJhZ2VfY3Vpc2luZSA8LSBhdmVyYWdlX3Njb3JlcyAlPiUgZ3JvdXBfYnkoQ1VJU0lORS5ERVNDUklQVElPTikgJT4lIG5hLm9taXQgJT4lCiAgZHBseXI6OnN1bW1hcml6ZShhdmVyYWdlX3Njb3JlID0gbWVhbihTQ09SRSkpCmF2ZXJhZ2VfY3Vpc2luZSA8LSBhcnJhbmdlKGF2ZXJhZ2VfY3Vpc2luZSwgLWF2ZXJhZ2Vfc2NvcmUpCmBgYAoKYGBge3IgZWNobz1GQUxTRX0KbiA8LSBucm93KGF2ZXJhZ2VfY3Vpc2luZSkKYmVzdDEwIDwtIGF2ZXJhZ2VfY3Vpc2luZVsobi0gMTApOm4sXQpiZXN0MTAgPC0gYmVzdDEwW29yZGVyKGJlc3QxMCRhdmVyYWdlX3Njb3JlKSxdCgpnZ3Bsb3QoYmVzdDEwLCBhZXMocmVvcmRlcih4ID0gQ1VJU0lORS5ERVNDUklQVElPTiwgLWF2ZXJhZ2Vfc2NvcmUpLCBhdmVyYWdlX3Njb3JlLCBmaWxsID0gQ1VJU0lORS5ERVNDUklQVElPTikpICsgZ2VvbV9iYXIoc3RhdD0naWRlbnRpdHknKSArIGNvb3JkX2ZsaXAoKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICdub25lJykrZ2d0aXRsZSgiQXZlcmFnZSBTY29yZSBvZiB0b3AgMTAgY3Vpc2luZXMiKSt4bGFiKCJDdWlzaW5lIERlc2NyaXB0aW9uIikreWxhYigiQXZlcmFnZSBTY29yZSIpK2dlb21fdGV4dChhZXMobGFiZWwgPSBzcHJpbnRmKCIlLjJmIiwgYXZlcmFnZV9zY29yZSkpLHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAxKSwjcG9zaXRpb249cG9zaXRpb25fc3RhY2sodmp1c3Q9MC41KQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2anVzdCA9IDAuNSwgc2l6ZSA9IDQpCmBgYAoKYGBge3IgZWNobyA9IEZBTFNFfQp3b3JzdDEwIDwtIGF2ZXJhZ2VfY3Vpc2luZVsxOjEwLF0KCmdncGxvdCh3b3JzdDEwLCBhZXMocmVvcmRlcih4ID0gQ1VJU0lORS5ERVNDUklQVElPTiwgLS1hdmVyYWdlX3Njb3JlKSwgYXZlcmFnZV9zY29yZSwgZmlsbCA9IENVSVNJTkUuREVTQ1JJUFRJT04pKSArIGdlb21fYmFyKHN0YXQ9J2lkZW50aXR5JykgKyBjb29yZF9mbGlwKCkgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAnbm9uZScpK2dndGl0bGUoIkF2ZXJhZ2UgU2NvcmUgb2YgV29yc3QgMTAgY3Vpc2luZXMiKSt4bGFiKCJDdWlzaW5lIERlc2NyaXB0aW9uIikreWxhYigiQXZlcmFnZSBTY29yZSIpK2dlb21fdGV4dChhZXMobGFiZWwgPSBzcHJpbnRmKCIlLjJmIiwgYXZlcmFnZV9zY29yZSkpLHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAxKSkKYGBgCgpJdCBpcyBpbnRlcmVzdGluZyB0aGF0IE5vdCBMaXN0ZWQvTm90IEFwcGxpY2FibGUgYW5kIE90aGVyIG1hZGUgaXQgdG8gdGhlIHRvcCAxMCBidXQgdGhlcmUgeW91IGhhdmUgaXQsIHRoZSBiZXN0IGFuZCB3b3JzdCBjdWlzaW5lcyBiYXNlZCB1cG9uIHRoZWlyIGF2ZXJhZ2Ugc2NvcmVzLgoKIyMgTWFpbiBBbmFseXNpcwpBZnRlciBhbmFseXppbmcgdGhlIHF1YWxpdHkgb2YgdGhlIGRhdGEgc2V0LCB3ZSBnb3QgcmlkIG9mIGRhdGEgaW4gd2hpY2ggdGhlIEJvcm91Z2ggaXMgbWlzc2luZyBhbmQgdGhlIHllYXIgaXMgYmVmb3JlIDIwMTMuCgpgYGB7cn0KVmlvbGF0aW9uc0RhdGEgPC0gVmlvbGF0aW9uc0RhdGEgJT4lIGZpbHRlciAoQk9STyAhPSAiTWlzc2luZyIpClZpb2xhdGlvbnNEYXRhIDwtIFZpb2xhdGlvbnNEYXRhICU+JSBmaWx0ZXIoCiAgYXMubnVtZXJpYyhmb3JtYXQoSU5TUEVDVElPTi5EQVRFICwgJyVZJykpID4gMjAxMikKYGBgCgpOb3cgd2UgY2FuIGdldCBhIGJldHRlciBwaWN0dXJlIG9mIHRoZSB0b3RhbCBudW1iZXIgb2YgaW5zcGVjdGlvbnMgYnkgeWVhciBhbmQgYm9yb3VnaC4KYGBge3J9CmJvcm91Z2hQbG90IDwtIGdncGxvdChWaW9sYXRpb25zRGF0YSwgYWVzKEJPUk8sZmlsbD1CT1JPKSkKYm9yb3VnaFBsb3QgKyBnZW9tX2JhcigpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikgKyAKICBmYWNldF93cmFwKH5mYWN0b3IoYXMubnVtZXJpYyggZm9ybWF0KElOU1BFQ1RJT04uREFURSAsICclWScpKSkpICsgCiAgZ2d0aXRsZSgiVG90YWwgSW5zcGVjdGlvbnMgZnJvbSAyMDEzLTIwMTcgaW4gZWFjaCBCb3JvdWdoIikgKwogIHhsYWIoIkJvcm91Z2giKSArIHlsYWIoIk51bWJlciBvZiBJbnNwZWN0aW9ucyIpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQpgYGAKQWZ0ZXIgMjAxMywgdGhlcmUgc2VlbXMgdG8gYmUgYSBjb25zaXN0ZW50IGFtb3VudCBvZiBpbnNwZWN0aW9ucyBhY3Jvc3MgdGhlIHllYXJzLiBUaGUgbnVtYmVyIG9mIGluc3BlY3Rpb25zIGJ5IGJvcm91Z2ggYWxzbyBzZWVtcyB0byBtYWtlIHNlbnNlIHNpbmNlIHdlIGV4cGVjdCBNYW5oYXR0YW4gdG8gaGF2ZSB0aGUgbGFyZ2VzdCBudW1iZXIgb2YgcmVzdHVhcmFudHMuCgpOZXh0LCB3ZSB0b29rIGEgbG9vayBhdCB0aGUgZ3JhZGUgZGlzdHJpYnV0aW9uIGJ5IGJvcm91Z2guCmBgYHtyLGZpZy53aWR0aD04LGZpZy5oZWlnaHQ9M30KaW5zcGVjdGlvbl9ncmFkZXMgPC0gVmlvbGF0aW9uc0RhdGEgJT4lIHNlbGVjdCgtQ0FNSVMsIC1EQkEsIC1CVUlMRElORywgLVNUUkVFVCwgLVpJUENPREUsIC1QSE9ORSwgLUFDVElPTiwgLVZJT0xBVElPTi5DT0RFLCAtVklPTEFUSU9OLkRFU0NSSVBUSU9OLCAtQ1JJVElDQUwuRkxBRywgLVNDT1JFLCAtR1JBREUuREFURSwgLVJFQ09SRC5EQVRFLCAtSU5TUEVDVElPTi5UWVBFLC1DVUlTSU5FLkRFU0NSSVBUSU9OKQoKaW5zcGVjdGlvbl9ncmFkZXNfd295ZWFyPC1pbnNwZWN0aW9uX2dyYWRlcyAlPiUgc2VsZWN0KC1JTlNQRUNUSU9OLkRBVEUpCgppbnNwZWN0aW9uX2dyYWRlc193b3llYXIgPC0gaW5zcGVjdGlvbl9ncmFkZXNfd295ZWFyICU+JSBnYXRoZXIoa2V5LCB2YWx1ZSwgLUJPUk8pICU+JSBncm91cF9ieShCT1JPLCBrZXksIHZhbHVlKSAlPiUgdGFsbHkgJT4lIHNwcmVhZCh2YWx1ZSwgbiwgZmlsbCA9IDApCm5hbWVzKGluc3BlY3Rpb25fZ3JhZGVzX3dveWVhcilbbmFtZXMoaW5zcGVjdGlvbl9ncmFkZXNfd295ZWFyKT09ImtleSJdIDwtICJncmFkZSIKbmFtZXMoaW5zcGVjdGlvbl9ncmFkZXNfd295ZWFyKVtuYW1lcyhpbnNwZWN0aW9uX2dyYWRlc193b3llYXIpPT0iIl0gPC0gImBVbmtub3duIgppbnNwZWN0aW9uX2dyYWRlc193b3llYXIgPC0gaW5zcGVjdGlvbl9ncmFkZXNfd295ZWFyICU+JSBnYXRoZXIoa2V5LCB2YWx1ZSwgLUJPUk8sLWdyYWRlKQpSZWxGcmVxPC1mdW5jdGlvbihtKXsKICAgKChtICkvc3VtKG0pKQp9CgppbnNwZWN0aW9uX2dyYWRlc193b3llYXI8LWluc3BlY3Rpb25fZ3JhZGVzX3dveWVhciAlPiUgZ3JvdXBfYnkoQk9STyxncmFkZSkgJT4lCiAgICBtdXRhdGUocGVyY2VudGFnZSA9ICh2YWx1ZS9zdW0odmFsdWUpKSoxMDApCmdncGxvdChpbnNwZWN0aW9uX2dyYWRlc193b3llYXIsIGFlcyhCT1JPLCBwZXJjZW50YWdlICxmaWxsPSBrZXkpKSArIAogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiwgcG9zaXRpb24gPSAiZG9kZ2UiKSArCiAgZ2d0aXRsZSgnJUdyYWRlIERpc3RyaWJ1dGlvbiBhY3Jvc3MgYm9yb3VnaHMnKSArIAogIGxhYnMoeCA9ICJCb3JvdWdoIiwgeSA9IlBlcmNlbnRhZ2UiKSArIGd1aWRlcyhmaWxsPWd1aWRlX2xlZ2VuZCh0aXRsZT0iR3JhZGUiKSkgICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjUsIGZhY2UgPSAiYm9sZCIpKQoKYGBgCldlIGluaXRpYWxseSBoeXBvdGhlc2l6ZWQgdGhhdCB3ZSB3b3VsZCBzZWUgYSBwYXR0ZXJuIGluIGdyYWRlIGRpc3RyaWJ1dGlvbiBieSBib3JvdWdoLCBob3dldmVyLCB0aGUgcGxvdCBzaG93cyB1cyB0aGF0IGdyYWRlIGRpc3RyaWJ1dGlvbnMgYXJlIGFsbW9zdCB0aGUgc2FtZSByZWdhcmRsZXNzIG9mIGJvcm91Z2guCgpgYGB7cixmaWcud2lkdGg9OH0KCmluc3BlY3Rpb25fZ3JhZGVzX3llYXI8LWluc3BlY3Rpb25fZ3JhZGVzJT4lIG11dGF0ZSh5ZWFyPWZhY3Rvcihhcy5udW1lcmljKGZvcm1hdChJTlNQRUNUSU9OLkRBVEUgLCAnJVknKSkpKQppbnNwZWN0aW9uX2dyYWRlc195ZWFyPC1pbnNwZWN0aW9uX2dyYWRlc195ZWFyJT4lIHNlbGVjdCgtSU5TUEVDVElPTi5EQVRFKQogaW5zcGVjdGlvbl9ncmFkZXNfeWVhciA8LSBpbnNwZWN0aW9uX2dyYWRlc195ZWFyICU+JSBnYXRoZXIoa2V5LCB2YWx1ZSwgLUJPUk8sLXllYXIpICU+JSBncm91cF9ieShCT1JPLHllYXIsIGtleSwgdmFsdWUpICU+JSAKICAgdGFsbHkgJT4lIHNwcmVhZCh2YWx1ZSwgbiwgZmlsbCA9IDApIyAlPiUgZ2F0aGVyKGJsYWgsIC1CT1JPLCAta2V5KSAjc3VtbWFyaXplKGFwcm9wID0gQS8oQStCK0MrKSkKbmFtZXMoaW5zcGVjdGlvbl9ncmFkZXNfeWVhcilbbmFtZXMoaW5zcGVjdGlvbl9ncmFkZXNfeWVhcik9PSJrZXkiXSA8LSAiZ3JhZGUiCm5hbWVzKGluc3BlY3Rpb25fZ3JhZGVzX3llYXIpW25hbWVzKGluc3BlY3Rpb25fZ3JhZGVzX3llYXIpPT0iIl0gPC0gImBVbmtub3duIgppbnNwZWN0aW9uX2dyYWRlc195ZWFyIDwtIGluc3BlY3Rpb25fZ3JhZGVzX3llYXIgJT4lIGdhdGhlcihrZXksIHZhbHVlLCAtQk9STywtZ3JhZGUsLXllYXIpClJlbEZyZXE8LWZ1bmN0aW9uKG0pewogICAoKG0gKS9zdW0obSkpCiB9Cmluc3BlY3Rpb25fZ3JhZGVzX3llYXI8LWluc3BlY3Rpb25fZ3JhZGVzX3llYXIgJT4lIGdyb3VwX2J5KEJPUk8sZ3JhZGUseWVhcikgJT4lCiAgICBtdXRhdGUocGVyY2VudGFnZSA9ICh2YWx1ZS9zdW0odmFsdWUpKSoxMDApCmdncGxvdChpbnNwZWN0aW9uX2dyYWRlc195ZWFyLCBhZXMoQk9STywgcGVyY2VudGFnZSAsZmlsbD0ga2V5KSkgKyAKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIHBvc2l0aW9uID0gImRvZGdlIikgK2ZhY2V0X3dyYXAofnllYXIsbnJvdz0yLG5jb2w9MykrCiAgZ3VpZGVzKGZpbGw9Z3VpZGVfbGVnZW5kKHRpdGxlPSJHcmFkZSIpKSsKICBnZ3RpdGxlKCIlR3JhZGUgRGlzdHJpYnV0aW9uIGJ5IEJvcm91Z2ggYW5kIFllYXIiKSsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjUsIGZhY2UgPSAiYm9sZCIpKQoKYGBgCgpBZGRpbmcgeWVhciB0byB0aGlzIGFuYWx5c2lzIHNob3dlZCB1cyBhbiBpbmNyZWFzZSBpbiB0aGUgcHJvcG9ydGlhbiBvZiBBcyBpbiBTdGF0ZW4gSXNsYW5kIGluIDIwMTUgYnV0IHNlZW1lZCBjb25zaXN0ZW50IHRocm91Z2hvdXQgdGhlIHJlc3Qgb2YgdGhlIHBsb3QuCgoKV2UgZGVjaWRlZCB0aGF0IGJvcm91Z2ggbWF5IGJlIHRvbyBnZW5lcmFsIGFuZCB0aHVzIGxvb2tlZCBhdCBncmFkZSBkaXN0cmlidXRpb24gYnkgemlwIGNvZGUgYWNyb3NzIHRoZSB2YXJpb3VzIHllYXJzLiBXZSB1c2VkIGEgaGVhdCBtYXAgdG8gZG8gc28uCmBgYHtyLGZpZy5oZWlnaHQ9MjAsZmlnLndpZHRoPTd9CmxpYnJhcnkodmlyaWRpcykKbm9uWWVhckRhdGFGb3JIZWF0TWFwPC1WaW9sYXRpb25zRGF0YSAlPiUgc2VsZWN0KEdSQURFLFpJUENPREUpCgpub25ZZWFyRGF0YUZvckhlYXRNYXAgPC0gbm9uWWVhckRhdGFGb3JIZWF0TWFwICU+JSBncm91cF9ieShHUkFERSxaSVBDT0RFKSAlPiUgdGFsbHkgClJlbEZyZXE8LWZ1bmN0aW9uKG0pewogICAoKG0gKS9zdW0obSkpCn0KCm5vblllYXJEYXRhRm9ySGVhdE1hcDwtICBub25ZZWFyRGF0YUZvckhlYXRNYXAgJT4lIGdyb3VwX2J5KFpJUENPREUpJT4lCiAgICBtdXRhdGUocGVyY2VudGFnZSA9IChuL3N1bShuKSkqMTAwKQoKZ2dwbG90KG5vblllYXJEYXRhRm9ySGVhdE1hcCwgYWVzKEdSQURFLCAKICAgICAgICAgICAgICAgICAgICAgICAgWklQQ09ERSwgZmlsbCA9IHBlcmNlbnRhZ2UpKSArCiAgZ2VvbV90aWxlKCkgKwogIHNjYWxlX2ZpbGxfdmlyaWRpcygpICsKICBnZ3RpdGxlKCJQZXJjZW50YWdlIEdyYWRlIERpc3RyaWJ1dGlvbiBieSBaaXBjb2RlXG4gIikreWxhYigiWmlwIENvZGUiKSArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDM1KSwgCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoY29sb3VyPSJncmV5MjAiLHNpemU9MTUsYW5nbGU9MCxoanVzdD0uNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmp1c3Q9LjUsZmFjZT0icGxhaW4iKSwgCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoY29sb3VyPSJncmV5MjAiLHNpemU9MTAsYW5nbGU9MCxoanVzdD0xLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZqdXN0PTAsZmFjZT0icGxhaW4iKSwgIAogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChjb2xvdXI9ImdyZXkyMCIsc2l6ZT0yNSxhbmdsZT0wLGhqdXN0PS41LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2anVzdD0wLGZhY2U9InBsYWluIiksCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KGNvbG91cj0iZ3JleTIwIixzaXplPTMwLGFuZ2xlPTkwLGhqdXN0PS41LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2anVzdD0uNSxmYWNlPSJwbGFpbiIpLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTIwKSwKICAgICAgICBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT0yMCksIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMSwgJ2luJykpCmBgYApJdCBpcyBpbnRlcmVzdGluZyB0byBub3RlIHRoYXQgbWlzc2luZyBncmFkZXMgYXJlIHByb2JhYmx5IHRoZSBtb3N0IHByb2JhYmxlIGluIGdlbmVyYWwuIFRoZXJlIGFyZSBzb21lIHppcCBjb2RlcyB3aXRoIGFsbW9zdCBubyBtaXNzaW5nIGdyYWRlcy4gVGhlIHJlc3R1YXJhbnRzIGluIHRob3NlIHNhbWUgemlwIGNvZGVzIHNlZW0gdG8gbW9zdGx5IGhhdmUgYWxsIEEgZ3JhZGVzLiBBbm90aGVyIGludGVyZXN0aW5nIHBvaW50IGlzIDEgemlwIGNvZGUgd2hpY2ggaGFzIGFsbCBOb3QgWWV0IEdyYWRlZCBncmFkZXMuIEluIGdlbmVyYWwgbWlzc2luZyBncmFkZXMgYW5kIGdyYWRlcyBvZiBhbiBBIHNlZW0gdGhlIG1vc3QgY29tbW9uLiBUaGlzIGlzIGZvbGxvd2VkIGJ5IGdyYWRlcyBvZiBhIEIuCgpUaGUgbmV4dCBwYXJ0IG9mIG91ciBhbmFseXNpcyB3YXMgdG8gbG9vayBhdCB0aGUgYXZlcmFnZSBzY29yZXMgb2YgZWFjaCBjdWlzaW5lLiBXaXRoIHRoaXMgaW5mb3JtYXRpb24sIHdlIGNhbiBoZWxwIGNvbnN1bWVycyBzZWUgd2hhdCBraW5kcyBvZiBlc3RhYmxpc2htZW50cyBoYXZlIHRoZSBiZXN0IGFuZCB3b3JzdCBzY29yZXMgb24gYXZlcmFnZS4gVGhpcyBpbiB0ZXJtIGNhbiBoZWxwIGEgY29uc3VtZXIgY2hvb3NlIGEgdHlwZSBvZiBjdWlzaW5lIHdoZW4gdGhleSBhcmUgaHVuZ3J5LgoKYGBge3IsZmlnLmhlaWdodD0yMCxmaWcud2lkdGg9NX0KYXZlcmFnZV9zY29yZXMgPC0gVmlvbGF0aW9uc0RhdGEgJT4lIHNlbGVjdCgtQ0FNSVMsIC1EQkEsIC1CVUlMRElORywgLVNUUkVFVCwgLVpJUENPREUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC1QSE9ORSwgLUlOU1BFQ1RJT04uREFURSwgLUFDVElPTiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLVZJT0xBVElPTi5DT0RFLCAtVklPTEFUSU9OLkRFU0NSSVBUSU9OLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAtQ1JJVElDQUwuRkxBRywgLUdSQURFLCAtR1JBREUuREFURSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLVJFQ09SRC5EQVRFLCAtSU5TUEVDVElPTi5UWVBFKQoKYXZlcmFnZV9jdWlzaW5lIDwtIGF2ZXJhZ2Vfc2NvcmVzICU+JSAgZ3JvdXBfYnkoQ1VJU0lORS5ERVNDUklQVElPTikgJT4lIG5hLm9taXQgJT4lCiAgZHBseXI6OnN1bW1hcml6ZShhdmVyYWdlX3Njb3JlID0gbWVhbihTQ09SRSkpCmF2ZXJhZ2VfY3Vpc2luZSA8LSBhcnJhbmdlKGF2ZXJhZ2VfY3Vpc2luZSwgLWF2ZXJhZ2Vfc2NvcmUpCgpnZ3Bsb3QoYXZlcmFnZV9jdWlzaW5lLCBhZXMocmVvcmRlcih4ID0gQ1VJU0lORS5ERVNDUklQVElPTiwgLS1hdmVyYWdlX3Njb3JlKSwgYXZlcmFnZV9zY29yZSxmaWxsPSJCbHVlIikpICsgZ2VvbV9iYXIoc3RhdD0naWRlbnRpdHknKSArIGNvb3JkX2ZsaXAoKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICdub25lJykrZ2d0aXRsZSgiQXZlcmFnZSBTY29yZXMgQWNyb3NzIEN1aXNpbmVzIikreGxhYigiQ3Vpc2luZSBEZXNjcmlwdGlvbiIpK3lsYWIoIkF2ZXJhZ2UgU2NvcmUiKStnZW9tX3RleHQoYWVzKGxhYmVsID0gc3ByaW50ZigiJS4yZiIsIGF2ZXJhZ2Vfc2NvcmUpKSxwb3NpdGlvbj1wb3NpdGlvbl9zdGFjayh2anVzdD0wLjUpLHZqdXN0ID0gMC41LCBzaXplID0gMykgKyB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyNSksIAogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChjb2xvdXI9ImdyZXkyMCIsc2l6ZT0yMCxhbmdsZT0wLGhqdXN0PS41LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2anVzdD0wLGZhY2U9InBsYWluIiksCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KGNvbG91cj0iZ3JleTIwIixzaXplPTIwLGFuZ2xlPTkwLGhqdXN0PS41LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2anVzdD0uNSxmYWNlPSJwbGFpbiIpKQpgYGAKCmBgYHtyfQp3b3JzdDEwIDwtIGF2ZXJhZ2VfY3Vpc2luZVsxOjEwLF0KCmdncGxvdCh3b3JzdDEwLCBhZXMocmVvcmRlcih4ID0gQ1VJU0lORS5ERVNDUklQVElPTiwgLS1hdmVyYWdlX3Njb3JlKSwgYXZlcmFnZV9zY29yZSwgZmlsbCA9IENVSVNJTkUuREVTQ1JJUFRJT04pKSArIGdlb21fYmFyKHN0YXQ9J2lkZW50aXR5JykgKyBjb29yZF9mbGlwKCkgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAnbm9uZScpK2dndGl0bGUoIkF2ZXJhZ2UgU2NvcmUgb2YgV29yc3QgMTAgY3Vpc2luZXMiKSt4bGFiKCJDdWlzaW5lIERlc2NyaXB0aW9uIikreWxhYigiQXZlcmFnZSBTY29yZSIpK2dlb21fdGV4dChhZXMobGFiZWwgPSBzcHJpbnRmKCIlLjJmIiwgYXZlcmFnZV9zY29yZSkpLHBvc2l0aW9uPXBvc2l0aW9uX3N0YWNrKHZqdXN0PTAuNSkpCmBgYAoKYGBge3J9Cm4gPC0gbnJvdyhhdmVyYWdlX2N1aXNpbmUpCmJlc3QxMCA8LSBhdmVyYWdlX2N1aXNpbmVbKG4tIDEwKTpuLF0KYmVzdDEwIDwtIGJlc3QxMFtvcmRlcihiZXN0MTAkYXZlcmFnZV9zY29yZSksXQoKZ2dwbG90KGJlc3QxMCwgYWVzKHJlb3JkZXIoeCA9IENVSVNJTkUuREVTQ1JJUFRJT04sIC1hdmVyYWdlX3Njb3JlKSwgYXZlcmFnZV9zY29yZSwgZmlsbCA9IENVSVNJTkUuREVTQ1JJUFRJT04pKSArIGdlb21fYmFyKHN0YXQ9J2lkZW50aXR5JykgKyBjb29yZF9mbGlwKCkgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAnbm9uZScpK2dndGl0bGUoIkF2ZXJhZ2UgU2NvcmUgb2YgdG9wIDEwIGN1aXNpbmVzIikreGxhYigiQ3Vpc2luZSBEZXNjcmlwdGlvbiIpK3lsYWIoIkF2ZXJhZ2UgU2NvcmUiKStnZW9tX3RleHQoYWVzKGxhYmVsID0gc3ByaW50ZigiJS4yZiIsIGF2ZXJhZ2Vfc2NvcmUpKSxwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMSksI3Bvc2l0aW9uPXBvc2l0aW9uX3N0YWNrKHZqdXN0PTAuNSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmp1c3QgPSAwLjUsIHNpemUgPSA0KQpgYGAKCkl0IGlzIGludGVyZXN0aW5nIHRoYXQgdGhlIG15c3RlcmlvdXMgIm5vdCBhcHBsaWNhYmxlIiIgY3Vpc2luZSBpcyBvbmUgb2YgdGhlIGJlc3QhCgpJbiB0aGlzIG5leHQgcGxvdCwgd2Ugd2FudGVkIHRvIHNlZSBpZiB0aGUgYXZlcmFnZSBzY29yZSBzaWduaWZpY2FudGx5IGRpZmZlcmVkIGJ5IEJvcm91Z2guCmBgYHtyfQphdmVyYWdlX2Jvcm91Z2ggPC0gYXZlcmFnZV9zY29yZXMgJT4lICBncm91cF9ieShCT1JPKSAlPiUgbmEub21pdCAlPiUKICBkcGx5cjo6c3VtbWFyaXplKGF2ZXJhZ2Vfc2NvcmUgPSBtZWFuKFNDT1JFKSkKCmdncGxvdChhdmVyYWdlX2Jvcm91Z2gsIGFlcyhyZW9yZGVyKHggPSBCT1JPLCAtLWF2ZXJhZ2Vfc2NvcmUpLCBhdmVyYWdlX3Njb3JlLCBmaWxsID0gQk9STykpICsgZ2VvbV9iYXIoc3RhdD0naWRlbnRpdHknKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICdub25lJykrZ2d0aXRsZSgiQXZlcmFnZSBTY29yZSBhY3Jvc3MgYm9yb3VnaHMiKSt4bGFiKCJCb3JvdWdoIikreWxhYigiQXZlcmFnZSBTY29yZSIpK2dlb21fdGV4dChhZXMobGFiZWwgPSBzcHJpbnRmKCIlLjJmIiwgYXZlcmFnZV9zY29yZSkpLHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAxKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmp1c3QgPSAtMC41LCBzaXplID0gMykKYGBgCgpBbHRob3VnaCB3ZSBzZWUgYSBzbGlnaHQgZGlmZmVyZW5jZSwgdGhlIGJvcm91Z2hzIGhhdmUgYXBwcm94aW1hdGVseSB0aGUgc2FtZSBhdmVyYWdlIHNjb3JlLiBTdGF0ZW4gSXNsYW5kIG1heSBiZSB0aGUgb25lIGV4Y2VwdGlvbi4gV2UgYWxzbyBmYWNldGVkIGJ5IHllYXIgdG8gc2VlIGlmIHRoYXQgbWFkZSBhIGRpZmZlcmVuY2UsIGJ1dCB0aGUgcmVzdWx0cyB3ZXJlIGVzc2VudGlhbGx5IHRoZSBzYW1lIGFzIGluIHRoZSBwbG90IGFib3ZlLgoKU28gZmFyIHdlIGxvb2tlZCBhdCBncmFkZXMgYW5kIHNjb3JlcyBidXQgbm90IHRoZSBhY3R1YWwgdmlvbGF0aW9ucy4gV2hhcmUgYXJlIHRoZSB0b3AgdmlvbGF0aW9ucyByZXN0YXVyYW50cyB1c3VhbGx5IGZhY2U/CmBgYHtyLGZpZy53aWR0aD0xMn0KCnZpb2xhdGlvbnM8LSBWaW9sYXRpb25zRGF0YSAlPiUgc2VsZWN0KC1DQU1JUywgLURCQSwgLUJVSUxESU5HLCAtU1RSRUVULCAtWklQQ09ERSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLVBIT05FLCAtSU5TUEVDVElPTi5EQVRFLCAtQUNUSU9OLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAtVklPTEFUSU9OLkNPREUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC1DUklUSUNBTC5GTEFHLCAtR1JBREUsIC1HUkFERS5EQVRFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAtUkVDT1JELkRBVEUsIC1JTlNQRUNUSU9OLlRZUEUpCgp2cyA8LSB2aW9sYXRpb25zICU+JSAgZ3JvdXBfYnkoVklPTEFUSU9OLkRFU0NSSVBUSU9OKSAlPiUgbmEub21pdCAlPiUKICBkcGx5cjo6c3VtbWFyaXplKGNvdW50ID0gbigpKQp2cyA8LSBhcnJhbmdlKHZzLCAtY291bnQpCgp0b3B2aW9sYXRpb25zIDwtIHZzWzE6MTAsXQoKbGlicmFyeShzdHJpbmdyKQp0b3B2aW9sYXRpb25zJHZpb2wgPSBzdHJfd3JhcCh0b3B2aW9sYXRpb25zJFZJT0xBVElPTi5ERVNDUklQVElPTiwgd2lkdGggPSAxNSkKCmdncGxvdCh0b3B2aW9sYXRpb25zLCBhZXMocmVvcmRlcih2aW9sLCAtY291bnQpLCBjb3VudCxmaWxsPXZpb2wpKSArIGdlb21fYmFyKHN0YXQ9J2lkZW50aXR5JykgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAnbm9uZScpK2dndGl0bGUoIlRvcCAxMCB2aW9sYXRpb25zIFxuIikreGxhYigiVmlvbGF0aW9uIGRlc2NyaXB0aW9uIikreWxhYigiY291bnQiKStnZW9tX3RleHQoYWVzKGxhYmVsID0gc3ByaW50ZigiJS4wZiIsIGNvdW50KSksCiBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMSksIHZqdXN0ID0gLTAuNSwgc2l6ZSA9IDcpICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gNDAsIGZhY2UgPSAiYm9sZCIpLCAKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChjb2xvdXI9ImdyZXkyMCIsc2l6ZT0yMCxhbmdsZT0wLGhqdXN0PS41LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2anVzdD0uNSxmYWNlPSJwbGFpbiIpLCAKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChjb2xvdXI9ImdyZXkyMCIsc2l6ZT0zMCxhbmdsZT0wLGhqdXN0PTEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmp1c3Q9MCxmYWNlPSJwbGFpbiIpLCAgCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KGNvbG91cj0iZ3JleTIwIixzaXplPTMwLGFuZ2xlPTAsaGp1c3Q9LjUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZqdXN0PTAsZmFjZT0icGxhaW4iKSwKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoY29sb3VyPSJncmV5MjAiLHNpemU9MzAsYW5nbGU9OTAsaGp1c3Q9LjUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZqdXN0PS41LGZhY2U9InBsYWluIikpCmBgYAoKV2UgYWxzbyBoeXBvdGhlc2l6ZWQgdGhhdCB0aGUgdHlwZSBvZiBpbnNwZWN0aW9ucyB3b3VsZCBnZW5lcmFsbHkgdmFyeSBieSBCb3JvdWdoIGJ1dCBldmVuIHRoaXMgd2FzIG1vc3RseSBjb25zaXN0ZW50LgpgYGB7cixmaWcuaGVpZ2h0PTYsIG1lc3NhZ2UgPSBGQUxTRX0KCiBsaWJyYXJ5KHZpcmlkaXMpCm1vczwtIFZpb2xhdGlvbnNEYXRhICU+JSBzZWxlY3QoLUNBTUlTLCAtREJBLCAtQlVJTERJTkcsIC1TVFJFRVQsIC1aSVBDT0RFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC1QSE9ORSwgLUFDVElPTiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAtVklPTEFUSU9OLkNPREUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLUNSSVRJQ0FMLkZMQUcsIC1HUkFERSwgLUdSQURFLkRBVEUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLVJFQ09SRC5EQVRFLCAtU0NPUkUsIC1DVUlTSU5FLkRFU0NSSVBUSU9OLCAtVklPTEFUSU9OLkRFU0NSSVBUSU9OKQptb3MkeWVhciA8LSBmYWN0b3IoYXMubnVtZXJpYyggZm9ybWF0KG1vcyRJTlNQRUNUSU9OLkRBVEUgLCAnJVknKSkpCm1vcyA8LSBtb3MgJT4lIHNlbGVjdCgtSU5TUEVDVElPTi5EQVRFKQoKYXZlcmFnZV9tb3MgPC0gbW9zICU+JSBncm91cF9ieShCT1JPLCB5ZWFyLCBJTlNQRUNUSU9OLlRZUEUpICU+JSB0YWxseSAlPiUKIGdyb3VwX2J5KEJPUk8sIHllYXIpICAlPiUgCiBtdXRhdGUocGVyY2VudGFnZSA9IG4gLyBzdW0obikpCiNhdmVyYWdlX2N1aXNpbmUgPC0gYXJyYW5nZShhdmVyYWdlX2N1aXNpbmUsIC1hdmVyYWdlX3Njb3JlKQoKbGlicmFyeSh2Y2QpCmF2ZXJhZ2VfbW9zIDwtIGF2ZXJhZ2VfbW9zICU+JSBzZWxlY3QoLW4pCgoKZ2dwbG90KGF2ZXJhZ2VfbW9zLCBhZXMoQk9STywgCiAgICAgICAgICAgICAgICAgICAgICAgSU5TUEVDVElPTi5UWVBFLCBmaWxsID0gcGVyY2VudGFnZSkpICsKIGdlb21fdGlsZSgpICsKIHNjYWxlX2ZpbGxfdmlyaWRpcygpICsKICNmYWNldF93cmFwKH5CT1JPKQogZ2d0aXRsZSgiQXZlcmFnZSBWaW9sYXRpb24gU2NvcmUgYnkgWmlwIENvZGVcbiAiKSsgeGxhYignQm9yb3VnaCcpICsKIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDMwLCBmYWNlID0gImJvbGQiKSwgCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoY29sb3VyPSJncmV5MjAiLHNpemU9MjAsYW5nbGU9MCxoanVzdD0uNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmp1c3Q9LjUsZmFjZT0icGxhaW4iKSwgCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoY29sb3VyPSJncmV5MjAiLHNpemU9MTUsYW5nbGU9MCxoanVzdD0xLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZqdXN0PTAsZmFjZT0icGxhaW4iKSwgIAogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChjb2xvdXI9ImdyZXkyMCIsc2l6ZT0yNSxhbmdsZT0wLGhqdXN0PS41LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2anVzdD0wLGZhY2U9InBsYWluIiksCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KGNvbG91cj0iZ3JleTIwIixzaXplPTI1LGFuZ2xlPTkwLGhqdXN0PS41LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2anVzdD0uNSxmYWNlPSJwbGFpbiIpLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTMwKSwKICAgICAgICBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT0yMCksIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMSwgJ2luJykpCgpgYGAKT25lIHRoaW5nIHdlIG5vdGljZWQgd2FzIHRoYXQgU3RhdGVuIGlzbGFuZCBoYXMgdGhlIGxlYXN0IEN5Y2xlIEluc3BlY3Rpb24vSW5pdGlhbCBJbnNwZWN0aW9uLiBNYXliZSB0aGV5IHdlcmUgb3BlbmluZyB1cCB0aGUgbGVhc3QgbmV3IHJlc3R1YXJhbnRzLiBUaGV5IGFsc28gaGFkIHRoZSBtb3N0IGN5Y2xlIGluc3BlY3Rpb24vcmUtaW5zcGVjdGlvbiBwZXJjZW50YWdlLiBBcyB3ZSdsbCBzZWUgaW4gdGhlIG1hcHMgYmVsb3csIHRob3NlIHJlaW5zcGVjdGlvbnMgbWF5IGhhdmUgaGVscGVkIHJlc3RhdXJhbnRzIGluIHN0YXRlbiBpc2xhbmQgaW1wcm92ZSB0aGVpciBncmFkZXMgYW5kIHNjb3Jlcy4KCgpPbmUgZmFjdG9yIG9mIG91ciBkYXRhIHNldCB3ZSBoYXZlbid0IGRpc2N1c3NlZCB0b28gbXVjaCBpcyB0aGUgQ3JpdGljYWwgZmxhZywgc2F5aW5nIHdoZXRoZXIgb3Igbm90IGEgdmlvbGF0aW9uIGlzIGNyaXRpY2FsLiBPbmNlIGFnYWluLCB3ZSBhc3N1bWVkIHRoYXQgb3ZlciB0aGUgeWVhcnMgYW5kIGFjcm9zcyBkaWZmZXJlbnQgYm9yb3VnaHMsIHRoZXJlIHdvdWxkIGJlIHNvbWUgcGF0dGVybiBpbiBjcml0aWNhbCB2aW9sYXRpb25zLiBBcyBjYW4gYmUgaW5mZXJyZWQgZnJvbSB0aGUgZm9sbG93aW5nIHBsb3QsIHRoZXJlIGlzIG5vdC4KYGBge3IsZmlnLndpZHRoPTV9CkNyaXRpY2FsaXR5RGF0YTwtIFZpb2xhdGlvbnNEYXRhICU+JSBzZWxlY3QoQk9STyxJTlNQRUNUSU9OLkRBVEUsQ1JJVElDQUwuRkxBRykgJT4lIG5hLm9taXQoKQpDcml0aWNhbGl0eURhdGEkeWVhcjwtZmFjdG9yKGFzLm51bWVyaWMoIGZvcm1hdChDcml0aWNhbGl0eURhdGEkSU5TUEVDVElPTi5EQVRFICwgJyVZJykpKQojQ3JpdGljYWxpdHlEYXRhIDwtIENyaXRpY2FsaXR5RGF0YSAlPiVzZWxlY3QoLUlOU1BFQ1RJT04uREFURSkKCkNyaXRpY2FsaXR5RGF0YSA8LSBDcml0aWNhbGl0eURhdGEgJT4lc2VsZWN0KC1JTlNQRUNUSU9OLkRBVEUpICU+JSBnYXRoZXIoa2V5LCB2YWx1ZSwgLUJPUk8sIC15ZWFyKSAlPiUgZ3JvdXBfYnkoQk9STywgeWVhcixrZXksdmFsdWUpICU+JSB0YWxseSAlPiUgc3ByZWFkKHZhbHVlLCBuLCBmaWxsID0gMCkKbmFtZXMoQ3JpdGljYWxpdHlEYXRhKVs1XSA8LSAiTm90QXBwbGljYWJsZSIKbmFtZXMoQ3JpdGljYWxpdHlEYXRhKVs2XSA8LSAiTm9uQ3JpdGljYWwiCgpDcml0aWNhbGl0eURhdGFQZXJjZW50YWdlPC1Dcml0aWNhbGl0eURhdGEgJT4lIHN1bW1hcml6ZShjcml0aWNhbFBlcmNlbnQgPSBDcml0aWNhbC8oQ3JpdGljYWwrTm90QXBwbGljYWJsZStOb25Dcml0aWNhbCksIE5vdEFwcGxpY2FibGVQZXJjZW50ID0gTm90QXBwbGljYWJsZS8oQ3JpdGljYWwrTm90QXBwbGljYWJsZStOb25Dcml0aWNhbCksIE5vbkNyaXRpY2FsUGVyY2VudCA9IE5vbkNyaXRpY2FsLyhDcml0aWNhbCtOb3RBcHBsaWNhYmxlK05vbkNyaXRpY2FsKSkjCgpuYW1lcyhDcml0aWNhbGl0eURhdGFQZXJjZW50YWdlKVs0XSA8LSAiQ3JpdGljYWwiCm5hbWVzKENyaXRpY2FsaXR5RGF0YVBlcmNlbnRhZ2UpWzVdIDwtICJOb3RBcHBsaWNhYmxlIgpuYW1lcyhDcml0aWNhbGl0eURhdGFQZXJjZW50YWdlKVs2XSA8LSAiTm9uQ3JpdGljYWwiCkNyaXRpY2FsaXR5RGF0YVBlcmNlbnRhZ2U8LUNyaXRpY2FsaXR5RGF0YVBlcmNlbnRhZ2UlPiUgZ2F0aGVyKGtleTEsIHZhbHVlLCAtQk9STywgLXllYXIsLWtleSkKCgpnZ3Bsb3QoQ3JpdGljYWxpdHlEYXRhUGVyY2VudGFnZSwgYWVzKEJPUk8sIHZhbHVlLCBmaWxsID0ga2V5MSkpICsgCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJkb2RnZSIpICsgCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQxIikrIHhsYWIoIkJPUk9VR0giKSt5bGFiKCJDUklUSUNBTElUWSBQRVJDRU5UQUdFUyIpICt0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKSsgZ2d0aXRsZSgiR3JvdXBlZCBiYXJjaGFydCBvZiBncmFkZSBmcmVxdWVuY3kgaW4gZWFjaCBjdWlzaW5lIGNhdGVnb3J5IFxuIHdoZW4gdGhlcmUgd2FzIGEgdmlvbGF0aW9uIHJlcG9ydGVkIikrZmFjZXRfd3JhcCh+eWVhcixucm93PTIsbmNvbD0zKStndWlkZXMoZmlsbD1ndWlkZV9sZWdlbmQodGl0bGU9IkNyaXRpY2FsaXR5IFxuIGNhdGVnb3J5IikpCgpgYGAKV2UgYXR0ZW1wdGVkIHRvIGZ1cnRoZXIgYW5hbHl6ZSB0aGUgY3JpdGljYWwgZmxhZyBidXQgd2UgbGVhcm5lZCB0aGF0IHRoZSBjcml0aWNhbCBmbGFnIGRpZCBub3QgaGF2ZSB0b28gbXVjaCBvZiBhbiBpbXBhY3Qgb24gZ3JhZGUgb3Igc2NvcmVzLiBUaGVyZSB3YXMgYSBsb3Qgb2YgZGF0YSB3aXRoIGEgZ3JhZGUgb2YgQSBidXQgYSBDcml0aWNhbCBmbGFnIHdoaWxlIG90aGVycyB3aXRoIGEgdmVyeSBoaWdoIHNjb3JlIGJ5IG5vIGNyaXRpY2FsIGZsYWcuCgojIyBWSVNVQUxJU0lORyBEQVRBIFdJVEggTUFQUwoKRm9yIHRoZSByZW1haW5kZXIgb2YgdGhlIGFuYWx5c2lzLCB3ZSB3aWxsIGJlIHdvcmtpbmcgd2l0aCBUYWJsZWF1LiBXZSBjaG9zZSBUYWJsZWF1IGJlY2F1c2Ugd2Ugd2FudGVkIHRvIHBsb3QgZWxlZ2VudCBtYXBzLiBUYWJsZWF1IHByb3ZpZGVzIGEgc2ltcGxlciBhbmQgbW9yZSBlbGVnZW50IHdheSB0byBkbyBzbyB0aGFuIGluIFIuCgorIFBsZWFzZSBub3RlIHRoYXQgdGhlcmUgaXMgYSB0dXRvcmlhbCBmb3IgZGVyaXZpbmcgbWFwcyBmcm9tIGdlbmVyYXRlZCBkYXRzZXQgaW4gVGFibGVhdSBpbiB0aGUgZ2l0aHViIHJlcG9zaXRvcnkgYXMgQ2hvcm9wbGV0aE1hcHMuaHRtbCB1bmRlciB0aGUgIkZpbmFsUmVwb3J0IiBmb2xkZXIgaW4gdGhlIEdpdGh1YiBSZXBvc2l0b3J5LiBJdCB3YXMgY3JlYXRlZCBieSBvdXIgdmVyeSBvd24gTGFrc2h5YSBHYXJnLgoKVGhlIGNvZGUgY2h1bmtzIHdpbGwgZ2VuZXJhdGUgdGhlIGRhdGEgdGhhdCB3ZSB1cGxvYWQgdG8gVGFibGVhdS4gSW4gdGhlIGZvbGxvd2luZyBhbmFseXNpcywgd2UgZXhwbG9yZSB0aGUgcHJvcG9ydGlvbiBvZiBBIGdyYWRlcyBiYXNlZCBvbiBuZWlnaGJvcmhvb2RzIG92ZXIgdGhlIHllYXJzLgpgYGB7cixmaWcuaGVpZ2h0PTE1fQojIyMjI0dFTkVSQVRFIEdSQURFIFBST1BPRVJUSU9OIERBVEFTRVQgQlkgWUVBUiBGT1IgVEFCTEVBVSBQTE9UVElORwp6aXBkYXRhPC0gVmlvbGF0aW9uc0RhdGEgJT4lIHNlbGVjdCgtQ0FNSVMsIC1EQkEsIC1CVUlMRElORywgLVNUUkVFVCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLVBIT05FLCAtQUNUSU9OLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAtVklPTEFUSU9OLkNPREUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC1DUklUSUNBTC5GTEFHLCAtU0NPUkUsIC1HUkFERS5EQVRFLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAtUkVDT1JELkRBVEUsIC1JTlNQRUNUSU9OLlRZUEUsIC1WSU9MQVRJT04uREVTQ1JJUFRJT04sIC1DVUlTSU5FLkRFU0NSSVBUSU9OLCAtQk9STykgJT4lIG5hLm9taXQoKQp6aXBkYXRhJHllYXI8LWZhY3Rvcihhcy5udW1lcmljKCBmb3JtYXQoemlwZGF0YSRJTlNQRUNUSU9OLkRBVEUgLCAnJVknKSkpCnppcGRhdGFHcmFkZVBlcmNlbnRhZ2UgPC0gemlwZGF0YSAlPiVzZWxlY3QoLUlOU1BFQ1RJT04uREFURSkgJT4lZ2F0aGVyKGtleSwgdmFsdWUsIC1aSVBDT0RFLCAteWVhcikgJT4lIGdyb3VwX2J5KFpJUENPREUsIHllYXIsIGtleSwgdmFsdWUpICU+JQogIHRhbGx5ICU+JSBzcHJlYWQodmFsdWUsIG4sIGZpbGwgPSAwKSAlPiUgc3VtbWFyaXplKGFwcm9wID0gQS8oQStCK0MpLCBicHJvcCA9IEIvKEErQitDKSwgY3Byb3AgPSBDLyhBK0IrQykgKQoKIyBnZ3Bsb3QoemlwZGF0YUdyYWRlUGVyY2VudGFnZSwgYWVzKHJlb3JkZXIoeCA9IFpJUENPREUsIC0tYXByb3ApLCBhcHJvcCkpICsgZ2VvbV9iYXIoc3RhdD0naWRlbnRpdHknKSArIAojICAgY29vcmRfZmxpcCgpICsgZmFjZXRfd3JhcCh+eWVhcikKIyAgIHRoZW1lKCBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDMpKQpgYGAKCiMjIyBQUk9QT1JUSU9OUyBPRiBBIEdSQURFUyBBQ1JPU1MgVEhFIFlFQVJTCgpPdmVyIHRoZSB5ZWFycywgdGhlIHByb3BvcnRpb24gb2YgQSdzIGhhcyBpbmNyZWFzZWQsIGFzIHJlcHJlc2VudGVkIGJ5IHRoZSBkYXJrZXIgcmVkIHNoYWRpbmcgb2YgdGhlIG1hcC4gSXQgaXMgdG9vIGVhcmx5IHRvIHN0dWR5IDIwMTcgaW4gZGVwdGggZHVlIHRvIHRoZSBsaW1pdGVkIG51bWJlciBvZiBpbnNwZWN0aW9ucyBzbyBmYXIuIE5vdGUgdGhhdCAyMDE3IGRhdGEgbWFwcyBhcmUgb25seSBmb3IgdGhlIGZpcnN0IHF1YXJ0ZXIgYW5kIGFyZSBsaWtlbHkgdG8gY2hhbmdlLgoKYGBge3J9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCdBcHJvcDIwMTMucG5nJykKYGBgCgpgYGB7cn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoJ0Fwcm9wMjAxNC5wbmcnKQpgYGAKCmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygnQXByb3AyMDE1LnBuZycpCmBgYAoKYGBge3J9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCdBcHJvcDIwMTYucG5nJykKYGBgCgpgYGB7cn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoJ0Fwcm9wMjAxNy5wbmcnKQpgYGAKCiMjIyBQUk9QT1JUSU9OUyBPRiBCIEdSQURFUyBBQ1JPU1MgVEhFIFlFQVJTCgpMZXQncyBsb29rIGF0IGhvdyB0aGUgcHJvcG9ydGlvbiBvZiBCJ3MgY2hhbmdlLiBXZSBjYW4gc2VlIHRoYXQgb3ZlciB0aGUgeWVhcnMsIHRoZXJlIHNlZW0gdG8gYmUgbGVzcyBCJ3Mgd2hpY2ggbWFrZXMgc2Vuc2Ugc2luY2Ugb3ZlciB0aGUgeWVhcnMgd2UgaGF2ZSBtb3JlIGdyYWRlcyBvZiBhbiBBLiBOb3RlIHRoYXQgMjAxNyBkYXRhIG1hcHMgYXJlIG9ubHkgZm9yIHRoZSBmaXJzdCBxdWFydGVyIGFuZCBhcmUgbGlrZWx5IHRvIGNoYW5nZS4KCmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygnQnByb3AxLnBuZycpCmBgYAoKYGBge3J9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCdCcHJvcDIucG5nJykKYGBgCgpgYGB7cn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoJ0Jwcm9wMy5wbmcnKQpgYGAKCmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygnQnByb3A0LnBuZycpCmBgYAoKYGBge3J9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCdCcHJvcDUucG5nJykKYGBgCgoKIyMjIEFWRVJBR0UgU0NPUkVTIEJZIFpJUENPREUgT1ZFUiBUSEUgWUVBUlMKCkxldCdzIGxvb2sgYXQgdGhlIGF2ZXJhZ2Ugc2NvcmVzIGJ5IG5laWdoYm9yaG9vZC4gV2UgaGF2ZSBhbHJlYWR5IGRvbmUgc28gYnkgY3Vpc2luZS4KT3ZlciB0aGUgeWVhcnMsIHdlIGhhdmUgYSBsb3dlciBBdmVyYWdlIFNjb3JlLiBUaGVzZSBOWUMgaW5zcGVjdGlvbnMgbXVzdCBiZSBwcm9tcHRpbmcgcmVzdHVyYW50cyB0byBpbXByb3ZlIHRoZWlyIGZhY2lsaXRpZXMgYW5kIGZvbGxvdyByZWd1bGF0aW9ucyEKCk5vdGUgdGhhdCAyMDE3IGRhdGEgbWFwcyBhcmUgb25seSBmb3IgdGhlIGZpcnN0IHF1YXJ0ZXIgYW5kIGFyZSBsaWtlbHkgdG8gY2hhbmdlLgoKCmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygnQXZnU2NvcmUyMDEzLnBuZycpCmBgYAoKYGBge3J9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCdBdmdTY29yZTIwMTQucG5nJykKYGBgCgpgYGB7cn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoJ0F2Z1Njb3JlMjAxNS5wbmcnKQpgYGAKCmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygnQXZnU2NvcmUyMDE2LnBuZycpCmBgYAoKYGBge3J9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCdBdmdTY29yZTIwMTcucG5nJykKYGBgCgojIyMgQVZFUkFHRSBSRS1JTlNQRUNUSU9OUyBPVkVSIFRIRSBZRUFSUwoKV2UgZGVjaWRlZCB0byBzZWUgd2hpY2ggYXJlYXMgaGFkIHRoZSBoaWdoZXN0IGF2ZXJhZ2UgbnVtYmVyIG9mIHJlaW5zcGVjdGlvbnMuIE1heWJlIHRoaXMgY2FuIGV4cGxhaW4gdGhlIGJldHRlciBzY29yZXMgYW5kIGdyYWRlcyBvdmVyIHRpbWUuIEludGVyZXN0aW5nbHkgZW5vdWdoLCB0aGUgYXJlYXMgd2l0aCB0aGUgbW9zdCByZWluc3BlY3Rpb25zIHNlZW0gdG8gYmUgdGhlIG9uZXMgaW4gd2hpY2ggdGhlIGdyYWRlcyBhbmQgc2NvcmVzIGltcHJvdmVkLiBUaGUgc3lzdGVtIG9mIHJlaW5zcGVjdGlvbnMgbXVzdCBiZSB3b3JraW5nIQoKTm90ZSB0aGF0IDIwMTcgZGF0YSBtYXBzIGFyZSBvbmx5IGZvciB0aGUgZmlyc3QgcXVhcnRlciBhbmQgYXJlIGxpa2VseSB0byBjaGFuZ2UuCgoKYGBge3J9CiMjIyBEQVRBIEdFTkVSQVRJT04KbGlicmFyeShzdHJpbmdyKQpyZWluc3BlY3QgPC0gVmlvbGF0aW9uc0RhdGEgJT4lIHNlbGVjdCgtQ0FNSVMsIC1EQkEsIC1CVUlMRElORywgLVNUUkVFVCwgLUNVSVNJTkUuREVTQ1JJUFRJT04sIC1CT1JPLCAtU0NPUkUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAtUEhPTkUsIElOU1BFQ1RJT04uREFURSwgLUFDVElPTiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAtVklPTEFUSU9OLkNPREUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLUNSSVRJQ0FMLkZMQUcsIC1HUkFERSwgLUdSQURFLkRBVEUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLVJFQ09SRC5EQVRFKQpyZWluc3BlY3QkeWVhcjwtZmFjdG9yKGFzLm51bWVyaWMoIGZvcm1hdChyZWluc3BlY3QkSU5TUEVDVElPTi5EQVRFICwgJyVZJykpKQoKI2luc3BlY3Rpb25fdHlwZXMgPC0gSU5TUEVDVElPTi5UWVBFCnJlaW5zcGVjdCA8LSByZWluc3BlY3QgJT4lc2VsZWN0KC1JTlNQRUNUSU9OLkRBVEUpICAlPiUgbmEub21pdCAlPiUgZmlsdGVyKHN0cl9kZXRlY3QoSU5TUEVDVElPTi5UWVBFLCAiUmUtaW5zcGVjdGlvbiIpKSU+JWdyb3VwX2J5KFZJT0xBVElPTi5ERVNDUklQVElPTiwgeWVhciwgWklQQ09ERSApICAlPiUgdGFsbHkjIHN1bW1hcmlzZShyZSA9IHN1bShzdHJfY291bnQocmVpbnNwZWN0JElOU1BFQ1RJT04uVFlQRSwgIlJlLWluc3BlY3Rpb24iKSkpCmBgYAoKYGBge3J9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCdBdmdSZWluc3BlY3QyMDEzLnBuZycpCmBgYAoKYGBge3J9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCdBdmdSZWluc3BlY3QyMDE0LnBuZycpCmBgYAoKYGBge3J9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCdBdmdSZWluc3BlY3QyMDE1LnBuZycpCmBgYAoKYGBge3J9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCdBdmdSZWluc3BlY3QyMDE2LnBuZycpCmBgYAoKYGBge3J9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCdBdmdSZWluc3BlY3QyMDE3LnBuZycpCmBgYAoKIyMgU1RBUkJVQ0tTIE9SIERVTktJTiBET05VVFM/Pz8KYGBge3IsIGVjaG8gPSBGQUxTRX0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoJ3N2c2QuanBnJykKYGBgCgpBcyBhIGxhc3QgYml0IG9mIGFuYWx5c2lzLCB3ZSBkZWNpZGVkIHRvIGhlbHAgc2V0dGxlIGEgaHVnZSBkaWxlbW5hIDogV2hlcmUgc2hvdWxkIHlvdSBnZXQgeW91ciBjb2ZmZWUsIFN0YXJidWNrcyBvciBEdW5raW4gRG9udXRzPwoKYGBge3J9CiMjREFUQSBHRU5FUkFUSU9OIENPREUKbGlicmFyeShzdHJpbmdyKQpDaGFpbnNzRGY8LVZpb2xhdGlvbnNEYXRhJT4lIG11dGF0ZShpc1N0YXJidWNrcz1zdHJfZGV0ZWN0KERCQSwiU1RBUkJVQ0siKSkgJT4lIG11dGF0ZShpc0R1bmtpbj1zdHJfZGV0ZWN0KERCQSwiRFVOS0lOIikpCkNoYWluc3NEZiREQkFbQ2hhaW5zc0RmJGlzU3RhcmJ1Y2tzPT1UUlVFXTwtIlNUQVJCVUNLUyIKQ2hhaW5zc0RmJERCQVtDaGFpbnNzRGYkaXNEdW5raW49PVRSVUVdPC0iRFVOS0lOIgpDaGFpbnNzRGY8LUNoYWluc3NEZiU+JWZpbHRlcihEQkEgJWluJSBjKCJTVEFSQlVDS1MiLCJEVU5LSU4iKSkKQ2hhaW5zc0RmPC1DaGFpbnNzRGYlPiVzZWxlY3QoREJBLEJPUk8sSU5TUEVDVElPTi5EQVRFLFpJUENPREUsU0NPUkUsVklPTEFUSU9OLkRFU0NSSVBUSU9OLEdSQURFKQpDaGFpbnNzRGYkeWVhcjwtZmFjdG9yKGFzLm51bWVyaWMoIGZvcm1hdChDaGFpbnNzRGYkSU5TUEVDVElPTi5EQVRFICwgJyVZJykpKQpDaGFpbnNzRGY8LUNoYWluc3NEZiU+JXNlbGVjdCgtSU5TUEVDVElPTi5EQVRFKQpgYGAKCkFzIHlvdSBjYW4gc2VlLCBEdW5raW4gRG9udXRzIGhhcyBtb3JlIGNyaXRpY2FsIHZpb2xhdGlvbnMgdGhhbiBTdGFyYnVja3MgaW4gZXZlcnkgQm9yb3VnaC4gTm90aWNpYmxlIGRpZmZlcmVuY2VzIGFyZSBlc3BlY2lhbGx5IHNlZSBpbiBCcm9va2x5biBhbmQgTWFuaGF0dGFuLgoKYGBge3J9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCdEUzEucG5nJykKYGBgCgoKQm90aCBlc3RhYmxpc2htZW50cyBzaGFyZWQgdGhlIHNhbWUgdG9wIHZpb2xhdGlvbnMuIExldCdzIHNlZSB3aGF0IHBlcmNlbnRhZ2Ugb2YgdGhlc2UgdmlvbGF0aW9ucyBlYWNoIGhhcy4gCmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygnRFMyLnBuZycpCmBgYApPbmNlIGFnYWluLCBTdGFyYnVja3MgaXMgdGhlIHdpbm5lciEKCldoYXQgYWJvdXQgdGhlIGF2ZXJhZ2Ugc2NvcmU/CmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygnRFMzLnBuZycpCmBgYAoKUmVnYXJkbGVzIG9mIHRoZSB5ZWFyLCB0aGUgYXZlcmFnZSBzY29yZSBvZiBEdW5raW4gRG9udXRzIGhhcyBiZWVuIGhpZ2hlci4gVGhlIGhpZ2hlciB0aGUgc2NvcmUsIHRoZSB3b3JzZS4gTm90aWNpYWJsZSBkaWZmZXJlbmNlcyBhcmUgc2VlbiBpbiAyMDE1IGFuZCB0aGUgZmlyc3QgdGhyZWUgbW9udGhzIG9mIDIwMTcuCgpMZXQncyBzZWUgaWYgdGhlIEJvcm91Z2ggeW91J3JlIGluIHNob3VsZCBpbXBhY3QgeW91ciBjaG9pY2UuCmBgYHtyfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygnRFM0LnBuZycpCmBgYAoKIyMjIFdlIGd1ZXNzIHdoZW4geW91J3JlIGluIEJyb29rbHluLCBpdCBkb2Vzbid0IG1hdHRlciBidXQgZXZlcnl3aGVyZSBlbHNlLCBzdGljayB0byBTdGFyYnVja3MsIGVzcGVjaWFsbHkgeW91IFN0YXRlbiBJc2xhbmQgZm9sa3MhCgoKYGBge3IsIGVjaG8gPSBGQUxTRX0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoJ3dpbm5lci5qcGcnKQpgYGAKCiMjIENvbmNsdXNpb24KTWFueSBsaW1pdGF0aW9ucyBpbmNsdWRlZCB0aGUgbWlzc2luZyBkYXRhIGl0c2VsZi4gV2UgbGVhcm5lZCB0aGF0IHNvbWV0aW1lcywgd2hhdCBtYXkgc2VlbSBsaWtlIGFuIGludHVpdGl2ZSBoeXBvdGhlc2lzLCBpcyBhY3R1YWxseSBjb21wbGV0ZWx5IGZhbHNlLiBUaGVyZSB3ZXJlIG5vdCBhcyBtYW55IHBhdHRlcm5zIGFzIHdlIGFudGljaXBhdGVkIGluIHRlcm1zIG9mIEJvcm91Z2guIFRoZSBvbmx5IHRoaW5nIHdlIGRpZCBzZWUgaXMgdGhhdCBvdmVyIHRpbWUsIHRoZSBzY29yZSBhbmQgZ3JhZGUgaGFzIGluY3JlYXNlZCwgc2hvd2luZyB1cyB0aGF0IHRoZSBpbnNwZWN0aW9ucyBzZWVtIHRvIGJlIHdvcmtpbmcgYW5kIHRoYXQgcmVzdHVhcmFudHMgYXJlIGltcHJvdmluZyB0aGVpciBmYWNpbGl0aWVzIHRvIHJlY2VpZXZlIGEgYmV0dGVyIHNjb3JlIGFuZCBncmFkZS4gQWNjb3JkaW5nIHRvIHRoZSB3ZWJzaXRlIHdlIHJlY2VpdmVkIHRoZSBkYXRhIGZyb20sIHRocmVlIGZpZWxkcyBhcmUgc29vbiB0byBiZSBhZGRlZCBhcyBkYXRhIGxvZ2ljIGJlY29tZXMgYXZhaWxhYmxlIHRvIHBvcHVsYXRlIHRoZW0gYWNjdXJhdGVseS4gVGhvc2UgZmllbGRzIGFyZSBWSU9MQVRJT04gUE9JTlRTICh0aGUgcG9pbnRzIGFzc2lnbmVkIHRvIGEgdmlvbGF0aW9uIGJlZm9yZSBvciBhZnRlciBhZGp1ZGljYXRpb24sIGRlcGVuZGluZyBvbiB3aGV0aGVyIGFkanVkaWNhdGlvbiBoYXMgb2NjdXJyZWQpLCBGSU5FUyBUT1RBTCAodGhlIGZpbmUgYW1vdW50IGFmdGVyIGFkanVkaWNhdGlvbiksIGFuZCBERUNJU0lPTiBEQVRFIChhZGp1ZGljYXRpb24gZGF0ZSDigJMgb3IgZGF0ZSBhIGdyYWRlIGJlY29tZXMgZmluYWwpLiBXaXRoIHRoaXMgaW5mb3JtYXRpb24sIHdlIGNhbiBkbyBtb3JlIGFuYWx5c2lzIHRvIHNlZSB0aGUgZmluZXMgb2YgdmFyaW91cyB2aW9sYXRpb25zIGFuZCBsZWFybiBob3cgZWFjaCB2aW9sYXRpb24gYWN0dWFsbHkgYWZmZWN0cyB0aGUgc2NvcmUuIFdpdGggdGhhdCwgcmVzdGF1cmFudHMgY2FuIGZvY3VzIG9uIHRoZSBtYWluIHZpb2xhdGlvbnMgdG8gaW1wcm92ZSB0aGVpciBzY29yZXMgaW4gdGhlIG5leHQgaW5zcGVjdGlvbi4KCgoKCgo=